mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Timelion] Cancel discarded searches (#125255)
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
7bea08f1a4
commit
25b97bbac1
6 changed files with 76 additions and 31 deletions
|
@ -83,11 +83,17 @@ function TimelionExpressionInput({ value, setValue }: TimelionExpressionInputPro
|
|||
);
|
||||
|
||||
useEffect(() => {
|
||||
const abortController = new AbortController();
|
||||
if (kibana.services.http) {
|
||||
kibana.services.http.get<ITimelionFunction[]>('../api/timelion/functions').then((data) => {
|
||||
functionList.current = data;
|
||||
});
|
||||
kibana.services.http
|
||||
.get<ITimelionFunction[]>('../api/timelion/functions', { signal: abortController.signal })
|
||||
.then((data) => {
|
||||
functionList.current = data;
|
||||
});
|
||||
}
|
||||
return () => {
|
||||
abortController.abort();
|
||||
};
|
||||
}, [kibana.services.http]);
|
||||
|
||||
return (
|
||||
|
|
|
@ -54,7 +54,10 @@ export function getTimelionRequestHandler({
|
|||
uiSettings,
|
||||
http,
|
||||
timefilter,
|
||||
}: TimelionVisDependencies) {
|
||||
expressionAbortSignal,
|
||||
}: TimelionVisDependencies & {
|
||||
expressionAbortSignal: AbortSignal;
|
||||
}) {
|
||||
const timezone = getTimezone(uiSettings);
|
||||
|
||||
return async function ({
|
||||
|
@ -74,6 +77,12 @@ export function getTimelionRequestHandler({
|
|||
}): Promise<TimelionSuccessResponse> {
|
||||
const dataSearch = getDataSearch();
|
||||
const expression = visParams.expression;
|
||||
const abortController = new AbortController();
|
||||
const expressionAbortHandler = function () {
|
||||
abortController.abort();
|
||||
};
|
||||
|
||||
expressionAbortSignal.addEventListener('abort', expressionAbortHandler);
|
||||
|
||||
if (!expression) {
|
||||
throw new Error(
|
||||
|
@ -98,9 +107,7 @@ export function getTimelionRequestHandler({
|
|||
const untrackSearch =
|
||||
dataSearch.session.isCurrentSession(searchSessionId) &&
|
||||
dataSearch.session.trackSearch({
|
||||
abort: () => {
|
||||
// TODO: support search cancellations
|
||||
},
|
||||
abort: () => abortController.abort(),
|
||||
});
|
||||
|
||||
try {
|
||||
|
@ -124,6 +131,7 @@ export function getTimelionRequestHandler({
|
|||
}),
|
||||
}),
|
||||
context: executionContext,
|
||||
signal: abortController.signal,
|
||||
});
|
||||
} catch (e) {
|
||||
if (e && e.body) {
|
||||
|
@ -142,6 +150,7 @@ export function getTimelionRequestHandler({
|
|||
// call `untrack` if this search still belongs to current session
|
||||
untrackSearch();
|
||||
}
|
||||
expressionAbortSignal.removeEventListener('abort', expressionAbortHandler);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ import { KibanaContext, Query, TimeRange } from '../../../data/public';
|
|||
type Input = KibanaContext | null;
|
||||
type Output = Promise<Render<TimelionRenderValue>>;
|
||||
export interface TimelionRenderValue {
|
||||
visData: TimelionSuccessResponse;
|
||||
visData?: TimelionSuccessResponse;
|
||||
visType: 'timelion';
|
||||
visParams: TimelionVisParams;
|
||||
}
|
||||
|
@ -65,10 +65,12 @@ export const getTimelionVisualizationConfig = (
|
|||
required: false,
|
||||
},
|
||||
},
|
||||
async fn(input, args, { getSearchSessionId, getExecutionContext, variables }) {
|
||||
async fn(
|
||||
input,
|
||||
args,
|
||||
{ getSearchSessionId, getExecutionContext, variables, abortSignal: expressionAbortSignal }
|
||||
) {
|
||||
const { getTimelionRequestHandler } = await import('./async_services');
|
||||
const timelionRequestHandler = getTimelionRequestHandler(dependencies);
|
||||
|
||||
const visParams = {
|
||||
expression: args.expression,
|
||||
interval: args.interval,
|
||||
|
@ -77,17 +79,25 @@ export const getTimelionVisualizationConfig = (
|
|||
(variables?.embeddableTitle as string) ??
|
||||
getExecutionContext?.()?.description,
|
||||
};
|
||||
let visData: TimelionRenderValue['visData'];
|
||||
|
||||
const response = await timelionRequestHandler({
|
||||
timeRange: get(input, 'timeRange') as TimeRange,
|
||||
query: get(input, 'query') as Query,
|
||||
filters: get(input, 'filters') as Filter[],
|
||||
visParams,
|
||||
searchSessionId: getSearchSessionId(),
|
||||
executionContext: getExecutionContext(),
|
||||
});
|
||||
if (!expressionAbortSignal.aborted) {
|
||||
const timelionRequestHandler = getTimelionRequestHandler({
|
||||
...dependencies,
|
||||
expressionAbortSignal,
|
||||
});
|
||||
|
||||
response.visType = TIMELION_VIS_NAME;
|
||||
visData = await timelionRequestHandler({
|
||||
timeRange: get(input, 'timeRange') as TimeRange,
|
||||
query: get(input, 'query') as Query,
|
||||
filters: get(input, 'filters') as Filter[],
|
||||
visParams,
|
||||
searchSessionId: getSearchSessionId(),
|
||||
executionContext: getExecutionContext(),
|
||||
});
|
||||
|
||||
visData.visType = TIMELION_VIS_NAME;
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'render',
|
||||
|
@ -95,7 +105,7 @@ export const getTimelionVisualizationConfig = (
|
|||
value: {
|
||||
visParams,
|
||||
visType: TIMELION_VIS_NAME,
|
||||
visData: response,
|
||||
visData,
|
||||
},
|
||||
};
|
||||
},
|
||||
|
|
|
@ -33,7 +33,7 @@ export const getTimelionVisRenderer: (
|
|||
unmountComponentAtNode(domNode);
|
||||
});
|
||||
|
||||
const [seriesList] = visData.sheet;
|
||||
const seriesList = visData?.sheet[0];
|
||||
const showNoResult = !seriesList || !seriesList.list.length;
|
||||
|
||||
const VisComponent = deps.uiSettings.get(UI_SETTINGS.LEGACY_CHARTS_LIBRARY, false)
|
||||
|
@ -62,13 +62,15 @@ export const getTimelionVisRenderer: (
|
|||
<VisualizationContainer handlers={handlers} showNoResult={showNoResult}>
|
||||
<KibanaThemeProvider theme$={deps.theme.theme$}>
|
||||
<KibanaContextProvider services={{ ...deps }}>
|
||||
<VisComponent
|
||||
interval={visParams.interval}
|
||||
ariaLabel={visParams.ariaLabel}
|
||||
seriesList={seriesList}
|
||||
renderComplete={handlers.done}
|
||||
onBrushEvent={onBrushEvent}
|
||||
/>
|
||||
{seriesList && (
|
||||
<VisComponent
|
||||
interval={visParams.interval}
|
||||
ariaLabel={visParams.ariaLabel}
|
||||
seriesList={seriesList}
|
||||
renderComplete={handlers.done}
|
||||
onBrushEvent={onBrushEvent}
|
||||
/>
|
||||
)}
|
||||
</KibanaContextProvider>
|
||||
</KibanaThemeProvider>
|
||||
</VisualizationContainer>,
|
||||
|
|
|
@ -28,6 +28,12 @@ describe('es', () => {
|
|||
getIndexPatternsService: () => ({
|
||||
find: async () => [],
|
||||
}),
|
||||
request: {
|
||||
events: {
|
||||
aborted$: of(),
|
||||
},
|
||||
body: {},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -46,9 +52,11 @@ describe('es', () => {
|
|||
});
|
||||
|
||||
test('should call data search with sessionId, isRestore and isStored', async () => {
|
||||
const baseTlConfig = stubRequestAndServer({ rawResponse: esResponse });
|
||||
tlConfig = {
|
||||
...stubRequestAndServer({ rawResponse: esResponse }),
|
||||
...baseTlConfig,
|
||||
request: {
|
||||
...baseTlConfig.request,
|
||||
body: {
|
||||
searchSession: {
|
||||
sessionId: '1',
|
||||
|
|
|
@ -12,6 +12,12 @@ import Datasource from '../../lib/classes/datasource';
|
|||
import buildRequest from './lib/build_request';
|
||||
import toSeriesList from './lib/agg_response_to_series_list';
|
||||
|
||||
function getRequestAbortedSignal(aborted$) {
|
||||
const controller = new AbortController();
|
||||
aborted$.subscribe(() => controller.abort());
|
||||
return controller.signal;
|
||||
}
|
||||
|
||||
export default new Datasource('es', {
|
||||
hideFitArg: true,
|
||||
args: [
|
||||
|
@ -107,13 +113,17 @@ export default new Datasource('es', {
|
|||
|
||||
const body = buildRequest(config, tlConfig, scriptFields, runtimeFields, esShardTimeout);
|
||||
|
||||
// User may abort the request without waiting for the results
|
||||
// we need to handle this scenario by aborting underlying server requests
|
||||
const abortSignal = getRequestAbortedSignal(tlConfig.request.events.aborted$);
|
||||
|
||||
const resp = await tlConfig.context.search
|
||||
.search(
|
||||
body,
|
||||
{
|
||||
...tlConfig.request?.body.searchSession,
|
||||
},
|
||||
tlConfig.context
|
||||
{ ...tlConfig.context, abortSignal }
|
||||
)
|
||||
.toPromise();
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue