fix: concurrent requests not beeing cached

This commit is contained in:
Hazork 2021-09-19 20:14:44 -03:00
parent 6e61c0d5db
commit 1490bfc30b
3 changed files with 28 additions and 5 deletions

4
.vscode/launch.json vendored
View File

@ -10,7 +10,9 @@
"${workspaceRoot}/node_modules/jest/bin/jest.js",
// Linux:
// "${workspaceRoot}/node_modules/.bin/jest",
"--runInBand"
"--runInBand",
"--watch",
"request.test.ts"
],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",

View File

@ -1,5 +1,5 @@
import { AxiosCacheInstance, CacheRequestConfig } from '../axios/types';
import { CachedResponse } from '../storage/types';
import { CachedResponse, CachedStorageValue, LoadingStorageValue } from '../storage/types';
import { Deferred } from '../util/deferred';
import { CACHED_STATUS_CODE, CACHED_STATUS_TEXT } from '../util/status-codes';
import { AxiosInterceptor } from './types';
@ -27,10 +27,19 @@ export class CacheRequestInterceptor implements AxiosInterceptor<CacheRequestCon
const key = this.axios.generateKey(config);
// Assumes that the storage handled staled responses
const cache = await this.axios.storage.get(key);
let cache = await this.axios.storage.get(key);
// Not cached, continue the request, and mark it as fetching
if (cache.state == 'empty') {
emptyState: if (cache.state == 'empty') {
// This if catches concurrent access to a new key.
// The js event loop skips in the first await statement,
// so the next code block will be executed both if called
// from two places asynchronously.
if (this.axios.waiting[key]) {
cache = (await this.axios.storage.get(key)) as CachedStorageValue | LoadingStorageValue;
break emptyState;
}
// Create a deferred to resolve other requests for the same key when it's completed
this.axios.waiting[key] = new Deferred();

View File

@ -1,4 +1,5 @@
import { mockAxios } from '../mocks/axios';
import { StatusCodes } from '../../src';
import { axiosMock, mockAxios } from '../mocks/axios';
describe('test request interceptor', () => {
it('tests against specified methods', async () => {
@ -26,4 +27,15 @@ describe('test request interceptor', () => {
expect(cache.state).toBe('cached');
});
it('tests concurrent requests', async () => {
const axios = mockAxios();
const [resp1, resp2] = await Promise.all([axios.get(''), axios.get('')]);
expect(resp1).toHaveProperty('status', axiosMock.statusCode);
expect(resp1).toHaveProperty('statusText', axiosMock.statusText);
expect(resp2).toHaveProperty('status', StatusCodes.CACHED_STATUS_CODE);
expect(resp2).toHaveProperty('statusText', StatusCodes.CACHED_STATUS_TEXT);
});
});