Skip to content

Commit

Permalink
fix: concurrent requests not beeing cached
Browse files Browse the repository at this point in the history
  • Loading branch information
arthurfiorette committed Sep 19, 2021
1 parent 6e61c0d commit 1490bfc
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 5 deletions.
4 changes: 3 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
15 changes: 12 additions & 3 deletions src/interceptors/request.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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();

Expand Down
14 changes: 13 additions & 1 deletion test/interceptors/request.test.ts
Original file line number Diff line number Diff line change
@@ -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 () => {
Expand Down Expand Up @@ -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);
});
});

0 comments on commit 1490bfc

Please sign in to comment.