Commit 93051179 by Hugo Häggmark Committed by GitHub

BackendSrv: Fixes queue countdown when unsubscribe is before response (#28323)

parent 5036c875
......@@ -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,
});
......
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();
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();
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment