Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Race condition fix for on the fly requests, improve cache implementat…
…ion and tests Co-authored-by: Goffert van Gool <ruphin@ruphin.net> Co-authored-by: Martin Pool <martin.pool@ing.com>
- Loading branch information
1 parent
dec9c75
commit 8795985
Showing
22 changed files
with
1,768 additions
and
959 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@lion/ajax': patch | ||
--- | ||
|
||
Fix cache session race condition for in-flight requests |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
--- | ||
'@lion/ajax': minor | ||
--- | ||
|
||
**BREAKING** public API changes: | ||
|
||
- Changed `timeToLive` to `maxAge` | ||
- Renamed `requestIdentificationFn` to `requestIdFunction` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import './typedef.js'; | ||
|
||
export default class Cache { | ||
constructor() { | ||
/** | ||
* @type {{ [requestId: string]: { createdAt: number, response: CacheResponse } }} | ||
* @private | ||
*/ | ||
this._cachedRequests = {}; | ||
} | ||
|
||
/** | ||
* Store an item in the cache | ||
* @param {string} requestId key by which the request is stored | ||
* @param {Response} response the cached response | ||
*/ | ||
set(requestId, response) { | ||
this._cachedRequests[requestId] = { | ||
createdAt: Date.now(), | ||
response, | ||
}; | ||
} | ||
|
||
/** | ||
* Retrieve an item from the cache | ||
* @param {string} requestId key by which the cache is stored | ||
* @param {number} maxAge maximum age of a cached request to serve from cache, in milliseconds | ||
* @returns {CacheResponse | undefined} | ||
*/ | ||
get(requestId, maxAge = 0) { | ||
const cachedRequest = this._cachedRequests[requestId]; | ||
if (!cachedRequest) { | ||
return; | ||
} | ||
const cachedRequestAge = Date.now() - cachedRequest.createdAt; | ||
if (Number.isFinite(maxAge) && cachedRequestAge < maxAge) { | ||
// eslint-disable-next-line consistent-return | ||
return cachedRequest.response; | ||
} | ||
} | ||
|
||
/** | ||
* Delete the item with the given requestId from the cache | ||
* @param {string } requestId the request id to delete from the cache | ||
*/ | ||
delete(requestId) { | ||
delete this._cachedRequests[requestId]; | ||
} | ||
|
||
/** | ||
* Delete all items from the cache that match given regex | ||
* @param {RegExp} regex a regular expression to match cache entries | ||
*/ | ||
deleteMatching(regex) { | ||
Object.keys(this._cachedRequests).forEach(requestId => { | ||
if (new RegExp(regex).test(requestId)) { | ||
this.delete(requestId); | ||
} | ||
}); | ||
} | ||
|
||
reset() { | ||
this._cachedRequests = {}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import './typedef.js'; | ||
|
||
export default class PendingRequestStore { | ||
constructor() { | ||
/** | ||
* @type {{ [requestId: string]: { promise: Promise<void>, resolve: (value?: any) => void } }} | ||
* @private | ||
*/ | ||
this._pendingRequests = {}; | ||
} | ||
|
||
/** | ||
* Creates a promise for a pending request with given key | ||
* @param {string} requestId | ||
*/ | ||
set(requestId) { | ||
if (this._pendingRequests[requestId]) { | ||
return; | ||
} | ||
/** @type {(value?: any) => void } */ | ||
let resolve; | ||
const promise = new Promise(_resolve => { | ||
resolve = _resolve; | ||
}); | ||
// @ts-ignore | ||
this._pendingRequests[requestId] = { promise, resolve }; | ||
} | ||
|
||
/** | ||
* Gets the promise for a pending request with given key | ||
* @param {string} requestId | ||
* @returns {Promise<void> | undefined} | ||
*/ | ||
get(requestId) { | ||
return this._pendingRequests[requestId]?.promise; | ||
} | ||
|
||
/** | ||
* Resolves the promise of a pending request that matches the given string | ||
* @param { string } requestId the requestId to resolve | ||
*/ | ||
resolve(requestId) { | ||
this._pendingRequests[requestId]?.resolve(); | ||
delete this._pendingRequests[requestId]; | ||
} | ||
|
||
/** | ||
* Resolves the promise of pending requests that match the given regex | ||
* @param { RegExp } regex an regular expression to match store entries | ||
*/ | ||
resolveMatching(regex) { | ||
Object.keys(this._pendingRequests).forEach(pendingRequestId => { | ||
if (regex.test(pendingRequestId)) { | ||
this.resolve(pendingRequestId); | ||
} | ||
}); | ||
} | ||
|
||
reset() { | ||
this._pendingRequests = {}; | ||
} | ||
} |
Oops, something went wrong.