Skip to content

Commit

Permalink
[ML] AIOps: Optimize initial load bundles. (elastic#198786)
Browse files Browse the repository at this point in the history
## Summary

Part of elastic#194171.

The AIOps plugin loads quite some bundle chunks on the first Kibana
load. On main it currently looks like this on page load:

![CleanShot 2024-11-04 at 14 56
52@2x](https://github.com/user-attachments/assets/cbabeaa2-848c-4970-aea5-b06befed0bec)

This means while the `aiops.plugin.js` bundle has just 10KB, we load
290KB in total via async bundles on every Kibana full page load.

This PR refactors how embeddables and UI actions get initialized to
avoid loading any additional async bundles on page load. This increases
`aiops.plugin.js` to ~15KB, but gets rid of all the rest!

![CleanShot 2024-11-04 at 15 02
10@2x](https://github.com/user-attachments/assets/557e240f-2c1c-434d-a936-dddb11ab68b6)

### Checklist

- [ ] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [ ] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
- [ ] This was checked for breaking API changes and was [labeled
appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#_add_your_labels)

(cherry picked from commit 33c303d)
  • Loading branch information
walterra committed Nov 8, 2024
1 parent 43e8c02 commit f138440
Show file tree
Hide file tree
Showing 11 changed files with 57 additions and 46 deletions.
2 changes: 1 addition & 1 deletion packages/kbn-optimizer/limits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ pageLoadAssetSize:
actions: 20000
advancedSettings: 27596
aiAssistantManagementSelection: 19146
aiops: 10000
aiops: 16000
alerting: 106936
apm: 64385
banners: 17946
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { createAction } from '@kbn/ui-actions-plugin/public';
import type { CoreStart } from '@kbn/core/public';
import { ACTION_CATEGORIZE_FIELD, type CategorizeFieldContext } from '@kbn/ml-ui-actions';
import type { AiopsPluginStartDeps } from '../../types';
import { showCategorizeFlyout } from './show_flyout';

export const createCategorizeFieldAction = (coreStart: CoreStart, plugins: AiopsPluginStartDeps) =>
createAction<CategorizeFieldContext>({
Expand All @@ -25,6 +24,7 @@ export const createCategorizeFieldAction = (coreStart: CoreStart, plugins: Aiops
},
execute: async (context: CategorizeFieldContext) => {
const { field, dataView, originatingApp, additionalFilter } = context;
const { showCategorizeFlyout } = await import('./show_flyout');
showCategorizeFlyout(field, dataView, coreStart, plugins, originatingApp, additionalFilter);
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

export type { LogCategorizationAppStateProps } from './log_categorization_app_state';
import { LogCategorizationAppState } from './log_categorization_app_state';
export { createCategorizeFieldAction } from './categorize_field_actions';

// required for dynamic import using React.lazy()
// eslint-disable-next-line import/no-default-export
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export async function showCategorizeFlyout(
): Promise<void> {
const { overlays, application, i18n } = coreStart;

return new Promise(async (resolve, reject) => {
return new Promise((resolve, reject) => {
try {
const onFlyoutClose = () => {
flyoutSession.close();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,6 @@ import type { DataView } from '@kbn/data-views-plugin/common';
import { DATA_VIEW_SAVED_OBJECT_TYPE } from '@kbn/data-views-plugin/common';
import type { ReactEmbeddableFactory } from '@kbn/embeddable-plugin/public';
import { i18n } from '@kbn/i18n';
import {
apiHasExecutionContext,
fetch$,
initializeTimeRange,
initializeTitles,
useBatchedPublishingSubjects,
} from '@kbn/presentation-publishing';

import fastIsEqual from 'fast-deep-equal';
import { cloneDeep } from 'lodash';
Expand Down Expand Up @@ -61,6 +54,14 @@ export const getChangePointChartEmbeddableFactory = (
return serializedState;
},
buildEmbeddable: async (state, buildApi, uuid, parentApi) => {
const {
apiHasExecutionContext,
fetch$,
initializeTimeRange,
initializeTitles,
useBatchedPublishingSubjects,
} = await import('@kbn/presentation-publishing');

const [coreStart, pluginStart] = await getStartServices();

const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,6 @@ import type { DataView } from '@kbn/data-views-plugin/common';
import { DATA_VIEW_SAVED_OBJECT_TYPE } from '@kbn/data-views-plugin/common';
import type { ReactEmbeddableFactory } from '@kbn/embeddable-plugin/public';
import { i18n } from '@kbn/i18n';
import {
apiHasExecutionContext,
fetch$,
initializeTimeRange,
initializeTitles,
useBatchedPublishingSubjects,
} from '@kbn/presentation-publishing';
import fastIsEqual from 'fast-deep-equal';
import { cloneDeep } from 'lodash';
import React, { useMemo } from 'react';
Expand Down Expand Up @@ -58,6 +51,14 @@ export const getPatternAnalysisEmbeddableFactory = (
return serializedState;
},
buildEmbeddable: async (state, buildApi, uuid, parentApi) => {
const {
apiHasExecutionContext,
fetch$,
initializeTimeRange,
initializeTitles,
useBatchedPublishingSubjects,
} = await import('@kbn/presentation-publishing');

const [coreStart, pluginStart] = await getStartServices();

const {
Expand Down
28 changes: 7 additions & 21 deletions x-pack/plugins/aiops/public/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,18 @@
import type { CoreStart, Plugin } from '@kbn/core/public';
import { type CoreSetup } from '@kbn/core/public';
import { firstValueFrom } from 'rxjs';
import { dynamic } from '@kbn/shared-ux-utility';

import { getChangePointDetectionComponent } from './shared_components';
import { LogCategorizationForDiscover as PatternAnalysisComponent } from './shared_lazy_components';
import type {
AiopsPluginSetup,
AiopsPluginSetupDeps,
AiopsPluginStart,
AiopsPluginStartDeps,
} from './types';
import { registerEmbeddables } from './embeddables';
import { registerAiopsUiActions } from './ui_actions';
import { registerChangePointChartsAttachment } from './cases/register_change_point_charts_attachment';

export type AiopsCoreSetup = CoreSetup<AiopsPluginStartDeps, AiopsPluginStart>;

Expand All @@ -27,20 +30,8 @@ export class AiopsPlugin
core: AiopsCoreSetup,
{ embeddable, cases, licensing, uiActions }: AiopsPluginSetupDeps
) {
Promise.all([
firstValueFrom(licensing.license$),
import('./embeddables'),
import('./ui_actions'),
import('./cases/register_change_point_charts_attachment'),
core.getStartServices(),
]).then(
([
license,
{ registerEmbeddables },
{ registerAiopsUiActions },
{ registerChangePointChartsAttachment },
[coreStart, pluginStart],
]) => {
Promise.all([firstValueFrom(licensing.license$), core.getStartServices()]).then(
([license, [coreStart, pluginStart]]) => {
const { canUseAiops } = coreStart.application.capabilities.ml;

if (license.hasAtLeast('platinum') && canUseAiops) {
Expand Down Expand Up @@ -69,12 +60,7 @@ export class AiopsPlugin
);
return getPatternAnalysisAvailable(plugins.licensing);
},
PatternAnalysisComponent: dynamic(
async () =>
import(
'./components/log_categorization/log_categorization_for_embeddable/log_categorization_for_discover_wrapper'
)
),
PatternAnalysisComponent,
};
}

Expand Down
20 changes: 20 additions & 0 deletions x-pack/plugins/aiops/public/shared_lazy_components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { EuiErrorBoundary, EuiSkeletonText } from '@elastic/eui';
import type { LogRateAnalysisAppStateProps } from './components/log_rate_analysis';
import type { LogRateAnalysisContentWrapperProps } from './components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content_wrapper';
import type { LogCategorizationAppStateProps } from './components/log_categorization';
import type { LogCategorizationEmbeddableWrapperProps } from './components/log_categorization/log_categorization_for_embeddable/log_categorization_for_discover_wrapper';
import type { ChangePointDetectionAppStateProps } from './components/change_point_detection';

const LogRateAnalysisAppStateLazy = React.lazy(() => import('./components/log_rate_analysis'));
Expand Down Expand Up @@ -58,6 +59,25 @@ export const LogCategorization: FC<LogCategorizationAppStateProps> = (props) =>
</LazyWrapper>
);

const LogCategorizationForDiscoverLazy = React.lazy(
() =>
import(
'./components/log_categorization/log_categorization_for_embeddable/log_categorization_for_discover_wrapper'
)
);

/**
* Lazy-wrapped LogCategorizationForDiscover React component
* @param {LogCategorizationEmbeddableWrapperProps} props - properties specifying the data on which to run the analysis.
*/
export const LogCategorizationForDiscover: FC<LogCategorizationEmbeddableWrapperProps> = (
props
) => (
<LazyWrapper>
<LogCategorizationForDiscoverLazy {...props} />
</LazyWrapper>
);

const ChangePointDetectionLazy = React.lazy(() => import('./components/change_point_detection'));
/**
* Lazy-wrapped ChangePointDetectionAppStateProps React component
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
*/

import { isPopulatedObject } from '@kbn/ml-is-populated-object';
import { apiIsOfType, type EmbeddableApiContext } from '@kbn/presentation-publishing';
import type { EmbeddableApiContext } from '@kbn/presentation-publishing';
import { apiIsOfType } from '@kbn/presentation-publishing/interfaces/has_type';
import { EMBEDDABLE_CHANGE_POINT_CHART_TYPE } from '@kbn/aiops-change-point-detection/constants';
import type { ChangePointEmbeddableApi } from '../embeddables/change_point_chart/types';

Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/aiops/public/ui_actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import type { CoreStart } from '@kbn/core/public';
import { createAddChangePointChartAction } from './create_change_point_chart';
import { createOpenChangePointInMlAppAction } from './open_change_point_ml';
import type { AiopsPluginStartDeps } from '../types';
import { createCategorizeFieldAction } from '../components/log_categorization';
import { createCategorizeFieldAction } from '../components/log_categorization/categorize_field_actions';
import { createAddPatternAnalysisEmbeddableAction } from './create_pattern_analysis_action';
import { createAddLogRateAnalysisEmbeddableAction } from './create_log_rate_analysis_actions';

Expand Down
13 changes: 8 additions & 5 deletions x-pack/plugins/aiops/public/ui_actions/open_change_point_ml.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@ import { IncompatibleActionError } from '@kbn/ui-actions-plugin/public';
import { i18n } from '@kbn/i18n';
import type { CoreStart } from '@kbn/core/public';
import type { TimeRange } from '@kbn/es-query';
import { apiHasParentApi, apiPublishesTimeRange } from '@kbn/presentation-publishing';
import type { ChangePointEmbeddableApi } from '../embeddables/change_point_chart/types';
import type { AiopsPluginStartDeps } from '../types';
import type { ChangePointChartActionContext } from './change_point_action_context';
import { isChangePointChartEmbeddableContext } from './change_point_action_context';

export const OPEN_CHANGE_POINT_IN_ML_APP_ACTION = 'openChangePointInMlAppAction';

export const getEmbeddableTimeRange = (
const getEmbeddableTimeRange = async (
embeddable: ChangePointEmbeddableApi
): TimeRange | undefined => {
): Promise<TimeRange | undefined> => {
const { apiHasParentApi, apiPublishesTimeRange } = await import('@kbn/presentation-publishing');

let timeRange = embeddable.timeRange$?.getValue();

if (!timeRange && apiHasParentApi(embeddable) && apiPublishesTimeRange(embeddable.parentApi)) {
Expand All @@ -45,6 +45,7 @@ export function createOpenChangePointInMlAppAction(
defaultMessage: 'Open in AIOps Labs',
}),
async getHref(context): Promise<string | undefined> {
const { isChangePointChartEmbeddableContext } = await import('./change_point_action_context');
if (!isChangePointChartEmbeddableContext(context)) {
throw new IncompatibleActionError();
}
Expand All @@ -57,7 +58,7 @@ export function createOpenChangePointInMlAppAction(
page: 'aiops/change_point_detection',
pageState: {
index: dataViewId.getValue(),
timeRange: getEmbeddableTimeRange(context.embeddable),
timeRange: await getEmbeddableTimeRange(context.embeddable),
fieldConfigs: [
{
fn: fn.getValue(),
Expand All @@ -69,6 +70,7 @@ export function createOpenChangePointInMlAppAction(
});
},
async execute(context) {
const { isChangePointChartEmbeddableContext } = await import('./change_point_action_context');
if (!isChangePointChartEmbeddableContext(context)) {
throw new IncompatibleActionError();
}
Expand All @@ -78,6 +80,7 @@ export function createOpenChangePointInMlAppAction(
}
},
async isCompatible(context) {
const { isChangePointChartEmbeddableContext } = await import('./change_point_action_context');
return isChangePointChartEmbeddableContext(context);
},
};
Expand Down

0 comments on commit f138440

Please sign in to comment.