mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 10:40:07 -04:00
[ML] Versioning AIOps APIs (#158806)
Adds versioning to the AIOps API. Versions are added to the server side routes and to the client side functions which call the routes. Updates API tests to add the API version to the request headers. The single API endpoint is already internal and now has been given the version '1'. **Internal APIs** `/internal/aiops/explain_log_rate_spikes`
This commit is contained in:
parent
648c669034
commit
423cb35fd7
14 changed files with 844 additions and 691 deletions
|
@ -51,6 +51,7 @@ export const PageReducerStream: FC = () => {
|
|||
typeof basePath
|
||||
>(
|
||||
`${basePath}/internal/response_stream/reducer_stream`,
|
||||
'1',
|
||||
{ compressResponse, simulateErrors },
|
||||
{ reducer: reducerStreamReducer, initialState }
|
||||
);
|
||||
|
|
|
@ -34,7 +34,7 @@ export const PageSimpleStringStream: FC = () => {
|
|||
const { dispatch, errors, start, cancel, data, isRunning } = useFetchStream<
|
||||
ApiSimpleStringStream,
|
||||
typeof basePath
|
||||
>(`${basePath}/internal/response_stream/simple_string_stream`, {
|
||||
>(`${basePath}/internal/response_stream/simple_string_stream`, '1', {
|
||||
compressResponse,
|
||||
timeout: 500,
|
||||
});
|
||||
|
|
|
@ -20,103 +20,110 @@ import {
|
|||
import { API_ENDPOINT } from '../../common/api';
|
||||
|
||||
export const defineReducerStreamRoute = (router: IRouter, logger: Logger) => {
|
||||
router.post(
|
||||
{
|
||||
router.versioned
|
||||
.post({
|
||||
path: API_ENDPOINT.REDUCER_STREAM,
|
||||
validate: {
|
||||
body: reducerStreamRequestBodySchema,
|
||||
access: 'internal',
|
||||
})
|
||||
.addVersion(
|
||||
{
|
||||
version: '1',
|
||||
validate: {
|
||||
request: {
|
||||
body: reducerStreamRequestBodySchema,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
async (context, request, response) => {
|
||||
const maxTimeoutMs = request.body.timeout ?? 250;
|
||||
const simulateError = request.body.simulateErrors ?? false;
|
||||
async (context, request, response) => {
|
||||
const maxTimeoutMs = request.body.timeout ?? 250;
|
||||
const simulateError = request.body.simulateErrors ?? false;
|
||||
|
||||
let logMessageCounter = 1;
|
||||
let logMessageCounter = 1;
|
||||
|
||||
function logDebugMessage(msg: string) {
|
||||
logger.debug(`Response Stream Example #${logMessageCounter}: ${msg}`);
|
||||
logMessageCounter++;
|
||||
}
|
||||
function logDebugMessage(msg: string) {
|
||||
logger.debug(`Response Stream Example #${logMessageCounter}: ${msg}`);
|
||||
logMessageCounter++;
|
||||
}
|
||||
|
||||
logDebugMessage('Starting stream.');
|
||||
logDebugMessage('Starting stream.');
|
||||
|
||||
let shouldStop = false;
|
||||
request.events.aborted$.subscribe(() => {
|
||||
logDebugMessage('aborted$ subscription trigger.');
|
||||
shouldStop = true;
|
||||
});
|
||||
request.events.completed$.subscribe(() => {
|
||||
logDebugMessage('completed$ subscription trigger.');
|
||||
shouldStop = true;
|
||||
});
|
||||
let shouldStop = false;
|
||||
request.events.aborted$.subscribe(() => {
|
||||
logDebugMessage('aborted$ subscription trigger.');
|
||||
shouldStop = true;
|
||||
});
|
||||
request.events.completed$.subscribe(() => {
|
||||
logDebugMessage('completed$ subscription trigger.');
|
||||
shouldStop = true;
|
||||
});
|
||||
|
||||
const { end, push, responseWithHeaders } = streamFactory<ReducerStreamApiAction>(
|
||||
request.headers,
|
||||
logger,
|
||||
request.body.compressResponse
|
||||
);
|
||||
const { end, push, responseWithHeaders } = streamFactory<ReducerStreamApiAction>(
|
||||
request.headers,
|
||||
logger,
|
||||
request.body.compressResponse
|
||||
);
|
||||
|
||||
const entities = [
|
||||
'kimchy',
|
||||
's1monw',
|
||||
'martijnvg',
|
||||
'jasontedor',
|
||||
'nik9000',
|
||||
'javanna',
|
||||
'rjernst',
|
||||
'jrodewig',
|
||||
];
|
||||
const entities = [
|
||||
'kimchy',
|
||||
's1monw',
|
||||
'martijnvg',
|
||||
'jasontedor',
|
||||
'nik9000',
|
||||
'javanna',
|
||||
'rjernst',
|
||||
'jrodewig',
|
||||
];
|
||||
|
||||
const actions = [...Array(19).fill('add'), 'delete'];
|
||||
const actions = [...Array(19).fill('add'), 'delete'];
|
||||
|
||||
if (simulateError) {
|
||||
actions.push('throw-error');
|
||||
actions.push('emit-error');
|
||||
}
|
||||
if (simulateError) {
|
||||
actions.push('throw-error');
|
||||
actions.push('emit-error');
|
||||
}
|
||||
|
||||
let progress = 0;
|
||||
let progress = 0;
|
||||
|
||||
async function pushStreamUpdate() {
|
||||
setTimeout(() => {
|
||||
try {
|
||||
progress++;
|
||||
async function pushStreamUpdate() {
|
||||
setTimeout(() => {
|
||||
try {
|
||||
progress++;
|
||||
|
||||
if (progress > 100 || shouldStop) {
|
||||
end();
|
||||
return;
|
||||
if (progress > 100 || shouldStop) {
|
||||
end();
|
||||
return;
|
||||
}
|
||||
|
||||
push(updateProgressAction(progress));
|
||||
|
||||
const randomEntity = entities[Math.floor(Math.random() * entities.length)];
|
||||
const randomAction = actions[Math.floor(Math.random() * actions.length)];
|
||||
|
||||
if (randomAction === 'add') {
|
||||
const randomCommits = Math.floor(Math.random() * 100);
|
||||
push(addToEntityAction(randomEntity, randomCommits));
|
||||
} else if (randomAction === 'delete') {
|
||||
push(deleteEntityAction(randomEntity));
|
||||
} else if (randomAction === 'throw-error') {
|
||||
// Throw an error. It should not crash Kibana!
|
||||
// It should be caught and logged to the Kibana server console.
|
||||
throw new Error('There was a (simulated) server side error!');
|
||||
} else if (randomAction === 'emit-error') {
|
||||
// Emit an error as a stream action.
|
||||
push(errorAction('(Simulated) error pushed to the stream'));
|
||||
return;
|
||||
}
|
||||
|
||||
pushStreamUpdate();
|
||||
} catch (e) {
|
||||
logger.error(e);
|
||||
}
|
||||
}, Math.floor(Math.random() * maxTimeoutMs));
|
||||
}
|
||||
|
||||
push(updateProgressAction(progress));
|
||||
// do not call this using `await` so it will run asynchronously while we return the stream already.
|
||||
pushStreamUpdate();
|
||||
|
||||
const randomEntity = entities[Math.floor(Math.random() * entities.length)];
|
||||
const randomAction = actions[Math.floor(Math.random() * actions.length)];
|
||||
|
||||
if (randomAction === 'add') {
|
||||
const randomCommits = Math.floor(Math.random() * 100);
|
||||
push(addToEntityAction(randomEntity, randomCommits));
|
||||
} else if (randomAction === 'delete') {
|
||||
push(deleteEntityAction(randomEntity));
|
||||
} else if (randomAction === 'throw-error') {
|
||||
// Throw an error. It should not crash Kibana!
|
||||
// It should be caught and logged to the Kibana server console.
|
||||
throw new Error('There was a (simulated) server side error!');
|
||||
} else if (randomAction === 'emit-error') {
|
||||
// Emit an error as a stream action.
|
||||
push(errorAction('(Simulated) error pushed to the stream'));
|
||||
return;
|
||||
}
|
||||
|
||||
pushStreamUpdate();
|
||||
} catch (e) {
|
||||
logger.error(e);
|
||||
}
|
||||
}, Math.floor(Math.random() * maxTimeoutMs));
|
||||
return response.ok(responseWithHeaders);
|
||||
}
|
||||
|
||||
// do not call this using `await` so it will run asynchronously while we return the stream already.
|
||||
pushStreamUpdate();
|
||||
|
||||
return response.ok(responseWithHeaders);
|
||||
}
|
||||
);
|
||||
);
|
||||
};
|
||||
|
|
|
@ -17,63 +17,70 @@ function timeout(ms: number) {
|
|||
}
|
||||
|
||||
export const defineSimpleStringStreamRoute = (router: IRouter, logger: Logger) => {
|
||||
router.post(
|
||||
{
|
||||
router.versioned
|
||||
.post({
|
||||
path: API_ENDPOINT.SIMPLE_STRING_STREAM,
|
||||
validate: {
|
||||
body: simpleStringStreamRequestBodySchema,
|
||||
access: 'internal',
|
||||
})
|
||||
.addVersion(
|
||||
{
|
||||
version: '1',
|
||||
validate: {
|
||||
request: {
|
||||
body: simpleStringStreamRequestBodySchema,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
async (context, request, response) => {
|
||||
const maxTimeoutMs = request.body.timeout ?? 250;
|
||||
async (context, request, response) => {
|
||||
const maxTimeoutMs = request.body.timeout ?? 250;
|
||||
|
||||
let shouldStop = false;
|
||||
request.events.aborted$.subscribe(() => {
|
||||
shouldStop = true;
|
||||
});
|
||||
request.events.completed$.subscribe(() => {
|
||||
shouldStop = true;
|
||||
});
|
||||
let shouldStop = false;
|
||||
request.events.aborted$.subscribe(() => {
|
||||
shouldStop = true;
|
||||
});
|
||||
request.events.completed$.subscribe(() => {
|
||||
shouldStop = true;
|
||||
});
|
||||
|
||||
const { end, push, responseWithHeaders } = streamFactory(
|
||||
request.headers,
|
||||
logger,
|
||||
request.body.compressResponse
|
||||
);
|
||||
const { end, push, responseWithHeaders } = streamFactory(
|
||||
request.headers,
|
||||
logger,
|
||||
request.body.compressResponse
|
||||
);
|
||||
|
||||
const text =
|
||||
'Elasticsearch is a search engine based on the Lucene library. It provides a distributed, multitenant-capable full-text search engine with an HTTP web interface and schema-free JSON documents. Elasticsearch is developed in Java and is dual-licensed under the source-available Server Side Public License and the Elastic license, while other parts fall under the proprietary (source-available) Elastic License. Official clients are available in Java, .NET (C#), PHP, Python, Apache Groovy, Ruby and many other languages. According to the DB-Engines ranking, Elasticsearch is the most popular enterprise search engine.';
|
||||
const text =
|
||||
'Elasticsearch is a search engine based on the Lucene library. It provides a distributed, multitenant-capable full-text search engine with an HTTP web interface and schema-free JSON documents. Elasticsearch is developed in Java and is dual-licensed under the source-available Server Side Public License and the Elastic license, while other parts fall under the proprietary (source-available) Elastic License. Official clients are available in Java, .NET (C#), PHP, Python, Apache Groovy, Ruby and many other languages. According to the DB-Engines ranking, Elasticsearch is the most popular enterprise search engine.';
|
||||
|
||||
const tokens = text.split(' ');
|
||||
const tokens = text.split(' ');
|
||||
|
||||
async function pushStreamUpdate() {
|
||||
try {
|
||||
if (shouldStop) {
|
||||
end();
|
||||
return;
|
||||
}
|
||||
|
||||
const token = tokens.shift();
|
||||
|
||||
if (token !== undefined) {
|
||||
push(`${token} `);
|
||||
await timeout(Math.floor(Math.random() * maxTimeoutMs));
|
||||
|
||||
if (!shouldStop) {
|
||||
pushStreamUpdate();
|
||||
async function pushStreamUpdate() {
|
||||
try {
|
||||
if (shouldStop) {
|
||||
end();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
end();
|
||||
|
||||
const token = tokens.shift();
|
||||
|
||||
if (token !== undefined) {
|
||||
push(`${token} `);
|
||||
await timeout(Math.floor(Math.random() * maxTimeoutMs));
|
||||
|
||||
if (!shouldStop) {
|
||||
pushStreamUpdate();
|
||||
}
|
||||
} else {
|
||||
end();
|
||||
}
|
||||
} catch (e) {
|
||||
logger.error(`There was an error: ${e.toString()}`);
|
||||
}
|
||||
} catch (e) {
|
||||
logger.error(`There was an error: ${e.toString()}`);
|
||||
}
|
||||
|
||||
// do not call this using `await` so it will run asynchronously while we return the stream already.
|
||||
pushStreamUpdate();
|
||||
|
||||
return response.ok(responseWithHeaders);
|
||||
}
|
||||
|
||||
// do not call this using `await` so it will run asynchronously while we return the stream already.
|
||||
pushStreamUpdate();
|
||||
|
||||
return response.ok(responseWithHeaders);
|
||||
}
|
||||
);
|
||||
);
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue