mirror of
https://github.com/grafana/grafana.git
synced 2025-02-14 01:23:32 -06:00
Logs: Cancel log volume query when the main query is canceled (#41856)
* Cancel log volume query when the main query is canceled * Test keeping complete log volume data when main query is canceled
This commit is contained in:
parent
177a0d69d1
commit
4e35d35e67
@ -3,12 +3,14 @@ import {
|
||||
addResultsToCache,
|
||||
cancelQueries,
|
||||
cancelQueriesAction,
|
||||
cleanLogsVolumeAction,
|
||||
clearCache,
|
||||
importQueries,
|
||||
queryReducer,
|
||||
runQueries,
|
||||
scanStartAction,
|
||||
scanStopAction,
|
||||
storeLogsVolumeDataProviderAction,
|
||||
} from './query';
|
||||
import { ExploreId, ExploreItemState, StoreState, ThunkDispatch } from 'app/types';
|
||||
import { interval, Observable, of } from 'rxjs';
|
||||
@ -127,7 +129,12 @@ describe('running queries', () => {
|
||||
.givenThunk(cancelQueries)
|
||||
.whenThunkIsDispatched(exploreId);
|
||||
|
||||
expect(dispatchedActions).toEqual([scanStopAction({ exploreId }), cancelQueriesAction({ exploreId })]);
|
||||
expect(dispatchedActions).toEqual([
|
||||
scanStopAction({ exploreId }),
|
||||
cancelQueriesAction({ exploreId }),
|
||||
storeLogsVolumeDataProviderAction({ exploreId, logsVolumeDataProvider: undefined }),
|
||||
cleanLogsVolumeAction({ exploreId }),
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@ -309,18 +316,24 @@ describe('reducer', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('logs volume', () => {
|
||||
describe('log volume', () => {
|
||||
let dispatch: ThunkDispatch,
|
||||
getState: () => StoreState,
|
||||
unsubscribes: Function[],
|
||||
mockLogsVolumeDataProvider: () => Observable<DataQueryResponse>;
|
||||
|
||||
beforeEach(() => {
|
||||
unsubscribes = [];
|
||||
mockLogsVolumeDataProvider = () => {
|
||||
return of(
|
||||
{ state: LoadingState.Loading, error: undefined, data: [] },
|
||||
{ state: LoadingState.Done, error: undefined, data: [{}] }
|
||||
);
|
||||
return ({
|
||||
subscribe: () => {
|
||||
const unsubscribe = jest.fn();
|
||||
unsubscribes.push(unsubscribe);
|
||||
return {
|
||||
unsubscribe,
|
||||
};
|
||||
},
|
||||
} as unknown) as Observable<DataQueryResponse>;
|
||||
};
|
||||
|
||||
const store: { dispatch: ThunkDispatch; getState: () => StoreState } = configureStore({
|
||||
@ -346,22 +359,9 @@ describe('reducer', () => {
|
||||
getState = store.getState;
|
||||
|
||||
setupQueryResponse(getState());
|
||||
unsubscribes = [];
|
||||
|
||||
mockLogsVolumeDataProvider = () => {
|
||||
return ({
|
||||
subscribe: () => {
|
||||
const unsubscribe = jest.fn();
|
||||
unsubscribes.push(unsubscribe);
|
||||
return {
|
||||
unsubscribe,
|
||||
};
|
||||
},
|
||||
} as unknown) as Observable<DataQueryResponse>;
|
||||
};
|
||||
});
|
||||
|
||||
it('should cancel any unfinished logs volume queries', async () => {
|
||||
it('should cancel any unfinished logs volume queries when a new query is run', async () => {
|
||||
await dispatch(runQueries(ExploreId.left));
|
||||
// first query is run automatically
|
||||
// loading in progress - one subscription created, not cleaned up yet
|
||||
@ -377,9 +377,56 @@ describe('reducer', () => {
|
||||
expect(unsubscribes[1]).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('should cancel log volume query when the main query is canceled', async () => {
|
||||
await dispatch(runQueries(ExploreId.left));
|
||||
expect(unsubscribes).toHaveLength(1);
|
||||
expect(unsubscribes[0]).not.toBeCalled();
|
||||
|
||||
await dispatch(cancelQueries(ExploreId.left));
|
||||
expect(unsubscribes).toHaveLength(1);
|
||||
expect(unsubscribes[0]).toBeCalled();
|
||||
|
||||
expect(getState().explore[ExploreId.left].logsVolumeData).toBeUndefined();
|
||||
expect(getState().explore[ExploreId.left].logsVolumeDataProvider).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should load logs volume after running the query', async () => {
|
||||
await dispatch(runQueries(ExploreId.left));
|
||||
expect(unsubscribes).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('should clean any incomplete log volume data when main query is canceled', async () => {
|
||||
mockLogsVolumeDataProvider = () => {
|
||||
return of({ state: LoadingState.Loading, error: undefined, data: [] });
|
||||
};
|
||||
await dispatch(runQueries(ExploreId.left));
|
||||
|
||||
expect(getState().explore[ExploreId.left].logsVolumeData).toBeDefined();
|
||||
expect(getState().explore[ExploreId.left].logsVolumeData!.state).toBe(LoadingState.Loading);
|
||||
expect(getState().explore[ExploreId.left].logsVolumeDataProvider).toBeDefined();
|
||||
|
||||
await dispatch(cancelQueries(ExploreId.left));
|
||||
expect(getState().explore[ExploreId.left].logsVolumeData).toBeUndefined();
|
||||
expect(getState().explore[ExploreId.left].logsVolumeDataProvider).toBeUndefined();
|
||||
});
|
||||
|
||||
it('keeps complete log volume data when main query is canceled', async () => {
|
||||
mockLogsVolumeDataProvider = () => {
|
||||
return of(
|
||||
{ state: LoadingState.Loading, error: undefined, data: [] },
|
||||
{ state: LoadingState.Done, error: undefined, data: [{}] }
|
||||
);
|
||||
};
|
||||
await dispatch(runQueries(ExploreId.left));
|
||||
|
||||
expect(getState().explore[ExploreId.left].logsVolumeData).toBeDefined();
|
||||
expect(getState().explore[ExploreId.left].logsVolumeData!.state).toBe(LoadingState.Done);
|
||||
expect(getState().explore[ExploreId.left].logsVolumeDataProvider).toBeDefined();
|
||||
|
||||
await dispatch(cancelQueries(ExploreId.left));
|
||||
expect(getState().explore[ExploreId.left].logsVolumeData).toBeDefined();
|
||||
expect(getState().explore[ExploreId.left].logsVolumeData!.state).toBe(LoadingState.Done);
|
||||
expect(getState().explore[ExploreId.left].logsVolumeDataProvider).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -110,11 +110,11 @@ export interface StoreLogsVolumeDataProvider {
|
||||
/**
|
||||
* Stores available logs volume provider after running the query. Used internally by runQueries().
|
||||
*/
|
||||
const storeLogsVolumeDataProviderAction = createAction<StoreLogsVolumeDataProvider>(
|
||||
export const storeLogsVolumeDataProviderAction = createAction<StoreLogsVolumeDataProvider>(
|
||||
'explore/storeLogsVolumeDataProviderAction'
|
||||
);
|
||||
|
||||
const cleanLogsVolumeAction = createAction<{ exploreId: ExploreId }>('explore/cleanLogsVolumeAction');
|
||||
export const cleanLogsVolumeAction = createAction<{ exploreId: ExploreId }>('explore/cleanLogsVolumeAction');
|
||||
|
||||
export interface StoreLogsVolumeDataSubscriptionPayload {
|
||||
exploreId: ExploreId;
|
||||
@ -221,9 +221,19 @@ export function addQueryRow(exploreId: ExploreId, index: number): ThunkResult<vo
|
||||
* Cancel running queries
|
||||
*/
|
||||
export function cancelQueries(exploreId: ExploreId): ThunkResult<void> {
|
||||
return (dispatch) => {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(scanStopAction({ exploreId }));
|
||||
dispatch(cancelQueriesAction({ exploreId }));
|
||||
dispatch(
|
||||
storeLogsVolumeDataProviderAction({
|
||||
exploreId,
|
||||
logsVolumeDataProvider: undefined,
|
||||
})
|
||||
);
|
||||
// clear any incomplete data
|
||||
if (getState().explore[exploreId]!.logsVolumeData?.state !== LoadingState.Done) {
|
||||
dispatch(cleanLogsVolumeAction({ exploreId }));
|
||||
}
|
||||
dispatch(stateSave());
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user