Add configuration to search without bfetch (#123942)

This commit is contained in:
Anton Dosov 2022-01-31 13:04:32 +01:00 committed by GitHub
parent 78643f495c
commit b6d2149e99
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 149 additions and 68 deletions

View file

@ -7,3 +7,4 @@
*/
export const DISABLE_BFETCH_COMPRESSION = 'bfetch:disableCompression';
export const DISABLE_BFETCH = 'bfetch:disable';

View file

@ -11,4 +11,4 @@ export type { StreamingResponseHandler } from './streaming';
export type { ItemBufferParams, TimedItemBufferParams, BatchedFunctionParams } from './buffer';
export { ItemBuffer, TimedItemBuffer, createBatchedFunction } from './buffer';
export type { ErrorLike, BatchRequestData, BatchResponseItem, BatchItemWrapper } from './batch';
export { DISABLE_BFETCH_COMPRESSION } from './constants';
export { DISABLE_BFETCH_COMPRESSION, DISABLE_BFETCH } from './constants';

View file

@ -14,6 +14,8 @@ export { split } from './streaming';
export type { BatchedFunc } from './batching/types';
export { DISABLE_BFETCH } from '../common/constants';
export function plugin(initializerContext: PluginInitializerContext) {
return new BfetchPublicPlugin(initializerContext);
}

View file

@ -9,13 +9,25 @@
import { i18n } from '@kbn/i18n';
import { UiSettingsParams } from 'src/core/server';
import { schema } from '@kbn/config-schema';
import { DISABLE_BFETCH_COMPRESSION } from '../common';
import { DISABLE_BFETCH_COMPRESSION, DISABLE_BFETCH } from '../common';
export function getUiSettings(): Record<string, UiSettingsParams<unknown>> {
return {
[DISABLE_BFETCH]: {
name: i18n.translate('bfetch.disableBfetch', {
defaultMessage: 'Disable request batching',
}),
value: false,
description: i18n.translate('bfetch.disableBfetchDesc', {
defaultMessage:
'Disables requests batching. This increases number of HTTP requests from Kibana, but allows to debug requests individually.',
}),
schema: schema.boolean(),
category: [],
},
[DISABLE_BFETCH_COMPRESSION]: {
name: i18n.translate('bfetch.disableBfetchCompression', {
defaultMessage: 'Disable Batch Compression',
defaultMessage: 'Disable batch compression',
}),
value: false,
description: i18n.translate('bfetch.disableBfetchCompressionDesc', {

View file

@ -21,9 +21,15 @@ import {
tap,
} from 'rxjs/operators';
import { PublicMethodsOf } from '@kbn/utility-types';
import { CoreSetup, CoreStart, ThemeServiceSetup, ToastsSetup } from 'kibana/public';
import {
CoreSetup,
CoreStart,
IHttpFetchError,
ThemeServiceSetup,
ToastsSetup,
} from 'kibana/public';
import { i18n } from '@kbn/i18n';
import { BatchedFunc, BfetchPublicSetup } from 'src/plugins/bfetch/public';
import { BatchedFunc, BfetchPublicSetup, DISABLE_BFETCH } from '../../../../bfetch/public';
import {
ENHANCED_ES_SEARCH_STRATEGY,
IAsyncSearchOptions,
@ -67,8 +73,9 @@ const MAX_CACHE_ITEMS = 50;
const MAX_CACHE_SIZE_MB = 10;
export class SearchInterceptor {
private uiSettingsSub: Subscription;
private uiSettingsSubs: Subscription[] = [];
private searchTimeout: number;
private bFetchDisabled: boolean;
private readonly responseCache: SearchResponseCache = new SearchResponseCache(
MAX_CACHE_ITEMS,
MAX_CACHE_SIZE_MB
@ -106,17 +113,21 @@ export class SearchInterceptor {
});
this.searchTimeout = deps.uiSettings.get(UI_SETTINGS.SEARCH_TIMEOUT);
this.bFetchDisabled = deps.uiSettings.get(DISABLE_BFETCH);
this.uiSettingsSub = deps.uiSettings
.get$(UI_SETTINGS.SEARCH_TIMEOUT)
.subscribe((timeout: number) => {
this.uiSettingsSubs.push(
deps.uiSettings.get$(UI_SETTINGS.SEARCH_TIMEOUT).subscribe((timeout: number) => {
this.searchTimeout = timeout;
});
}),
deps.uiSettings.get$(DISABLE_BFETCH).subscribe((bFetchDisabled: boolean) => {
this.bFetchDisabled = bFetchDisabled;
})
);
}
public stop() {
this.responseCache.clear();
this.uiSettingsSub.unsubscribe();
this.uiSettingsSubs.forEach((s) => s.unsubscribe());
}
/*
@ -266,13 +277,34 @@ export class SearchInterceptor {
options?: ISearchOptions
): Promise<IKibanaSearchResponse> {
const { abortSignal } = options || {};
return this.batchedFetch(
{
request,
options: this.getSerializableOptions(options),
},
abortSignal
);
if (this.bFetchDisabled) {
const { executionContext, strategy, ...searchOptions } = this.getSerializableOptions(options);
return this.deps.http
.post(`/internal/search/${strategy}${request.id ? `/${request.id}` : ''}`, {
signal: abortSignal,
context: executionContext,
body: JSON.stringify({
...request,
...searchOptions,
}),
})
.catch((e: IHttpFetchError<KibanaServerError>) => {
if (e?.body) {
throw e.body;
} else {
throw e;
}
}) as Promise<IKibanaSearchResponse>;
} else {
return this.batchedFetch(
{
request,
options: this.getSerializableOptions(options),
},
abortSignal
);
}
}
/**
@ -319,9 +351,12 @@ export class SearchInterceptor {
*/
public search({ id, ...request }: IKibanaSearchRequest, options: IAsyncSearchOptions = {}) {
const searchOptions = {
strategy: ENHANCED_ES_SEARCH_STRATEGY,
...options,
};
if (!searchOptions.strategy) {
searchOptions.strategy = ENHANCED_ES_SEARCH_STRATEGY;
}
const { sessionId, abortSignal } = searchOptions;
return this.createRequestHash$(request, searchOptions).pipe(

View file

@ -392,6 +392,10 @@ export const stackManagementSchema: MakeSchemaFrom<UsageStats> = {
type: 'boolean',
_meta: { description: 'Non-default value of setting.' },
},
'bfetch:disable': {
type: 'boolean',
_meta: { description: 'Non-default value of setting.' },
},
'visualization:visualize:legacyPieChartsLibrary': {
type: 'boolean',
_meta: { description: 'Non-default value of setting.' },

View file

@ -23,6 +23,7 @@ export interface UsageStats {
/**
* non-sensitive settings
*/
'bfetch:disable': boolean;
'bfetch:disableCompression': boolean;
'autocomplete:useTimeRange': boolean;
'autocomplete:valueSuggestionMethod': string;

View file

@ -7736,6 +7736,12 @@
"description": "Non-default value of setting."
}
},
"bfetch:disable": {
"type": "boolean",
"_meta": {
"description": "Non-default value of setting."
}
},
"visualization:visualize:legacyPieChartsLibrary": {
"type": "boolean",
"_meta": {

View file

@ -17,62 +17,82 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const toasts = getService('toasts');
describe('Search example', () => {
describe('with bfetch', () => {
testSearchExample();
});
describe('no bfetch', () => {
const kibanaServer = getService('kibanaServer');
before(async () => {
await kibanaServer.uiSettings.replace({
'bfetch:disable': true,
});
});
after(async () => {
await kibanaServer.uiSettings.unset('bfetch:disable');
});
testSearchExample();
});
const appId = 'searchExamples';
before(async function () {
await PageObjects.common.navigateToApp(appId, { insertTimestamp: false });
await comboBox.setCustom('dataViewSelector', 'logstash-*');
await comboBox.set('searchBucketField', 'geo.src');
await comboBox.set('searchMetricField', 'memory');
await PageObjects.timePicker.setAbsoluteRange(
'Mar 1, 2015 @ 00:00:00.000',
'Nov 1, 2015 @ 00:00:00.000'
);
});
beforeEach(async () => {
await toasts.dismissAllToasts();
await retry.waitFor('toasts gone', async () => {
return (await toasts.getToastCount()) === 0;
});
});
it('should have an other bucket', async () => {
await testSubjects.click('searchSourceWithOther');
await testSubjects.click('responseTab');
const codeBlock = await testSubjects.find('responseCodeBlock');
await retry.waitFor('get code block', async () => {
const visibleText = await codeBlock.getVisibleText();
const parsedResponse = JSON.parse(visibleText);
const buckets = parsedResponse.aggregations[1].buckets;
return (
buckets.length === 3 && buckets[2].key === '__other__' && buckets[2].doc_count === 9039
function testSearchExample() {
before(async function () {
await PageObjects.common.navigateToApp(appId, { insertTimestamp: false });
await comboBox.setCustom('dataViewSelector', 'logstash-*');
await comboBox.set('searchBucketField', 'geo.src');
await comboBox.set('searchMetricField', 'memory');
await PageObjects.timePicker.setAbsoluteRange(
'Mar 1, 2015 @ 00:00:00.000',
'Nov 1, 2015 @ 00:00:00.000'
);
});
});
it('should not have an other bucket', async () => {
await testSubjects.click('searchSourceWithoutOther');
await testSubjects.click('responseTab');
const codeBlock = await testSubjects.find('responseCodeBlock');
await retry.waitFor('get code block', async () => {
const visibleText = await codeBlock.getVisibleText();
const parsedResponse = JSON.parse(visibleText);
const buckets = parsedResponse.aggregations[1].buckets;
return buckets.length === 2;
beforeEach(async () => {
await toasts.dismissAllToasts();
await retry.waitFor('toasts gone', async () => {
return (await toasts.getToastCount()) === 0;
});
});
});
it('should handle warnings', async () => {
await testSubjects.click('searchWithWarning');
await retry.waitFor('', async () => {
const toastCount = await toasts.getToastCount();
return toastCount > 1;
it('should have an other bucket', async () => {
await testSubjects.click('searchSourceWithOther');
await testSubjects.click('responseTab');
const codeBlock = await testSubjects.find('responseCodeBlock');
await retry.waitFor('get code block', async () => {
const visibleText = await codeBlock.getVisibleText();
const parsedResponse = JSON.parse(visibleText);
const buckets = parsedResponse.aggregations[1].buckets;
return (
buckets.length === 3 && buckets[2].key === '__other__' && buckets[2].doc_count === 9039
);
});
});
const warningToast = await toasts.getToastElement(2);
const textEl = await warningToast.findByClassName('euiToastBody');
const text: string = await textEl.getVisibleText();
expect(text).to.contain('Watch out!');
});
it('should not have an other bucket', async () => {
await testSubjects.click('searchSourceWithoutOther');
await testSubjects.click('responseTab');
const codeBlock = await testSubjects.find('responseCodeBlock');
await retry.waitFor('get code block', async () => {
const visibleText = await codeBlock.getVisibleText();
const parsedResponse = JSON.parse(visibleText);
const buckets = parsedResponse.aggregations[1].buckets;
return buckets.length === 2;
});
});
it('should handle warnings', async () => {
await testSubjects.click('searchWithWarning');
await retry.waitFor('', async () => {
const toastCount = await toasts.getToastCount();
return toastCount > 1;
});
const warningToast = await toasts.getToastElement(2);
const textEl = await warningToast.findByClassName('euiToastBody');
const text: string = await textEl.getVisibleText();
expect(text).to.contain('Watch out!');
});
}
});
}