Alerting: Improve new list view performance (#108115)

kristina/correlation-migrate
Gilles De Mey 5 days ago committed by GitHub
parent c06c1b1e8a
commit 8cb6993fe6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 16
      public/app/features/alerting/unified/api/prometheusApi.ts
  2. 4
      public/app/features/alerting/unified/rule-list/PaginatedDataSourceLoader.tsx
  3. 38
      public/app/features/alerting/unified/rule-list/hooks/prometheusGroupsGenerator.ts
  4. 7
      public/app/features/alerting/unified/rule-list/hooks/useFilteredRulesIterator.ts

@ -118,18 +118,20 @@ export const prometheusApi = alertingApi.injectEndpoints({
export function usePopulateGrafanaPrometheusApiCache() {
const dispatch = useDispatch();
const populateGroupResponseCache = useCallback(
(group: GrafanaPromRuleGroupDTO) => {
const populateGroupsResponseCache = useCallback(
(groups: GrafanaPromRuleGroupDTO[]) => {
dispatch(
prometheusApi.util.upsertQueryData(
'getGrafanaGroups',
{ folderUid: group.folderUid, groupName: group.name },
{ data: { groups: [group] }, status: 'success' }
prometheusApi.util.upsertQueryEntries(
groups.map((group) => ({
endpointName: 'getGrafanaGroups',
arg: { folderUid: group.folderUid, groupName: group.name, limitAlerts: 0 },
value: { data: { groups: [group] }, status: 'success' },
}))
)
);
},
[dispatch]
);
return { populateGroupResponseCache };
return { populateGroupsResponseCache };
}

@ -51,9 +51,7 @@ function PaginatedGroupsLoader({ rulesSourceIdentifier, application, groupFilter
const hasFilters = Boolean(groupFilter || namespaceFilter);
const { uid, name } = rulesSourceIdentifier;
const prometheusGroupsGenerator = usePrometheusGroupsGenerator({
populateCache: hasFilters ? false : true,
});
const prometheusGroupsGenerator = usePrometheusGroupsGenerator();
// If there are no filters we can match one frontend page to one API page.
// However, if there are filters, we need to fetch more groups from the API to populate one frontend page

@ -1,10 +1,9 @@
import { useCallback } from 'react';
import { useDispatch } from 'app/types/store';
import { DataSourceRulesSourceIdentifier, RuleHealth } from 'app/types/unified-alerting';
import { PromAlertingRuleState, PromRuleGroupDTO } from 'app/types/unified-alerting-dto';
import { PromRulesResponse, prometheusApi } from '../../api/prometheusApi';
import { PromRulesResponse, prometheusApi, usePopulateGrafanaPrometheusApiCache } from '../../api/prometheusApi';
const { useLazyGetGroupsQuery, useLazyGetGrafanaGroupsQuery } = prometheusApi;
@ -22,8 +21,7 @@ interface FetchGroupsOptions {
groupNextToken?: string;
}
export function usePrometheusGroupsGenerator(hookOptions: UseGeneratorHookOptions = {}) {
const dispatch = useDispatch();
export function usePrometheusGroupsGenerator() {
const [getGroups] = useLazyGetGroupsQuery();
return useCallback(
@ -35,24 +33,12 @@ export function usePrometheusGroupsGenerator(hookOptions: UseGeneratorHookOption
...fetchOptions,
}).unwrap();
if (hookOptions.populateCache) {
response.data.groups.forEach((group) => {
dispatch(
prometheusApi.util.upsertQueryData(
'getGroups',
{ ruleSource: { uid: ruleSource.uid }, namespace: group.file, groupName: group.name },
{ data: { groups: [group] }, status: 'success' }
)
);
});
}
return response;
};
yield* genericGroupsGenerator(getRuleSourceGroupsWithCache, groupLimit);
},
[getGroups, dispatch, hookOptions.populateCache]
[getGroups]
);
}
@ -67,8 +53,8 @@ interface GrafanaFetchGroupsOptions extends FetchGroupsOptions {
}
export function useGrafanaGroupsGenerator(hookOptions: UseGeneratorHookOptions = {}) {
const dispatch = useDispatch();
const [getGrafanaGroups] = useLazyGetGrafanaGroupsQuery();
const { populateGroupsResponseCache } = usePopulateGrafanaPrometheusApiCache();
const getGroupsAndProvideCache = useCallback(
async (fetchOptions: GrafanaFetchGroupsOptions) => {
@ -78,25 +64,13 @@ export function useGrafanaGroupsGenerator(hookOptions: UseGeneratorHookOptions =
...fetchOptions.filter,
}).unwrap();
// This is not mandatory to preload ruler rules, but it improves the UX
// Because the user waits a bit longer for the initial load but doesn't need to wait for each group to be loaded
if (hookOptions.populateCache) {
const cacheAndRulerPreload = response.data.groups.map(async (group) => {
await dispatch(
prometheusApi.util.upsertQueryData(
'getGrafanaGroups',
{ folderUid: group.folderUid, groupName: group.name, limitAlerts: hookOptions.limitAlerts },
{ data: { groups: [group] }, status: 'success' }
)
);
});
await Promise.allSettled(cacheAndRulerPreload);
populateGroupsResponseCache(response.data.groups);
}
return response;
},
[getGrafanaGroups, dispatch, hookOptions.populateCache, hookOptions.limitAlerts]
[getGrafanaGroups, hookOptions.limitAlerts, hookOptions.populateCache, populateGroupsResponseCache]
);
return useCallback(

@ -15,7 +15,6 @@ import {
PromRuleGroupDTO,
} from 'app/types/unified-alerting-dto';
import { usePopulateGrafanaPrometheusApiCache } from '../../api/prometheusApi';
import { RulesFilter } from '../../search/rulesSearchParser';
import {
getDataSourceByUid,
@ -52,7 +51,6 @@ interface GetIteratorResult {
}
export function useFilteredRulesIteratorProvider() {
const { populateGroupResponseCache } = usePopulateGrafanaPrometheusApiCache();
const allExternalRulesSources = getExternalRulesSources();
const prometheusGroupsGenerator = usePrometheusGroupsGenerator();
@ -76,10 +74,7 @@ export function useFilteredRulesIteratorProvider() {
concatMap((groups) =>
groups
.filter((group) => groupFilter(group, normalizedFilterState))
.flatMap((group) => {
populateGroupResponseCache(group);
return group.rules.map((rule) => [group, rule] as const);
})
.flatMap((group) => group.rules.map((rule) => [group, rule] as const))
.filter(([, rule]) => ruleFilter(rule, normalizedFilterState))
.map(([group, rule]) => mapGrafanaRuleToRuleWithOrigin(group, rule))
),

Loading…
Cancel
Save