mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
BackendSrv: Fixes queue countdown when unsubscribe is before response (#28323)
This commit is contained in:
parent
5036c87540
commit
9305117902
@ -26,30 +26,28 @@ const getTestContext = () => {
|
||||
|
||||
const fetchMock = jest.fn().mockReturnValue(fetchResult);
|
||||
const setInProgressMock = jest.fn();
|
||||
const setDoneMock = jest.fn();
|
||||
|
||||
const queueMock: FetchQueue = ({
|
||||
add: jest.fn(),
|
||||
setInProgress: setInProgressMock,
|
||||
setDone: setDoneMock,
|
||||
setDone: jest.fn(),
|
||||
getUpdates: jest.fn(),
|
||||
} as unknown) as FetchQueue;
|
||||
|
||||
const responseQueue = new ResponseQueue(queueMock, fetchMock);
|
||||
|
||||
return { id, options, expects, fetchMock, setInProgressMock, setDoneMock, responseQueue, fetchResult };
|
||||
return { id, options, expects, fetchMock, setInProgressMock, responseQueue, fetchResult };
|
||||
};
|
||||
|
||||
describe('ResponseQueue', () => {
|
||||
describe('add', () => {
|
||||
describe('when called', () => {
|
||||
it('then the matching fetchQueue entry should be set to inProgress', () => {
|
||||
const { id, options, setInProgressMock, setDoneMock, responseQueue } = getTestContext();
|
||||
const { id, options, setInProgressMock, responseQueue } = getTestContext();
|
||||
|
||||
responseQueue.add(id, options);
|
||||
|
||||
expect(setInProgressMock.mock.calls).toEqual([['id']]);
|
||||
expect(setDoneMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('then a response entry with correct id should be published', done => {
|
||||
@ -81,14 +79,13 @@ describe('ResponseQueue', () => {
|
||||
|
||||
describe('and when the fetch Observable is completed', () => {
|
||||
it('then the matching fetchQueue entry should be set to Done', done => {
|
||||
const { id, options, responseQueue, setInProgressMock, setDoneMock } = getTestContext();
|
||||
const { id, options, responseQueue, setInProgressMock } = getTestContext();
|
||||
|
||||
subscribeTester({
|
||||
observable: responseQueue.getResponses(id).pipe(first()),
|
||||
expectCallback: data => {
|
||||
data.observable.subscribe().unsubscribe();
|
||||
expect(setInProgressMock.mock.calls).toEqual([['id']]);
|
||||
expect(setDoneMock.mock.calls).toEqual([['id']]);
|
||||
},
|
||||
doneCallback: done,
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { filter, finalize } from 'rxjs/operators';
|
||||
import { filter } from 'rxjs/operators';
|
||||
import { BackendSrvRequest, FetchResponse } from '@grafana/runtime';
|
||||
import { FetchQueue } from './FetchQueue';
|
||||
|
||||
@ -27,17 +27,7 @@ export class ResponseQueue {
|
||||
// Let the fetchQueue know that this id has started data fetching.
|
||||
fetchQueue.setInProgress(id);
|
||||
|
||||
this.responses.next({
|
||||
id,
|
||||
observable: fetch(options).pipe(
|
||||
// finalize is called whenever this observable is unsubscribed/errored/completed/canceled
|
||||
// https://rxjs.dev/api/operators/finalize
|
||||
finalize(() => {
|
||||
// Let the fetchQueue know that this id is done.
|
||||
fetchQueue.setDone(id);
|
||||
})
|
||||
),
|
||||
});
|
||||
this.responses.next({ id, observable: fetch(options) });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -65,10 +65,11 @@ export class BackendSrv implements BackendService {
|
||||
}
|
||||
|
||||
fetch<T>(options: BackendSrvRequest): Observable<FetchResponse<T>> {
|
||||
return new Observable(observer => {
|
||||
// We need to match an entry added to the queue stream with the entry that is eventually added to the response stream
|
||||
const id = uuidv4();
|
||||
// We need to match an entry added to the queue stream with the entry that is eventually added to the response stream
|
||||
const id = uuidv4();
|
||||
const fetchQueue = this.fetchQueue;
|
||||
|
||||
return new Observable(observer => {
|
||||
// Subscription is an object that is returned whenever you subscribe to an Observable.
|
||||
// You can also use it as a container of many subscriptions and when it is unsubscribed all subscriptions within are also unsubscribed.
|
||||
const subscriptions: Subscription = new Subscription();
|
||||
@ -89,6 +90,9 @@ export class BackendSrv implements BackendService {
|
||||
|
||||
// This returned function will be called whenever the returned Observable from the fetch<T> function is unsubscribed/errored/completed/canceled.
|
||||
return function unsubscribe() {
|
||||
// Change status to Done moved here from ResponseQueue because this unsubscribe was called before the responseQueue produced a result
|
||||
fetchQueue.setDone(id);
|
||||
|
||||
// When subscriptions is unsubscribed all the implicitly added subscriptions above are also unsubscribed.
|
||||
subscriptions.unsubscribe();
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user