Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
jaredwray committed Jan 14, 2025
2 parents 4ba7048 + fd4bb94 commit 6d1fd20
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 5 deletions.
4 changes: 2 additions & 2 deletions packages/cache-manager/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ const cache = createCache({ stores: [keyv] });
- **ttl**?: number - Default time to live in milliseconds.

The time to live in milliseconds. This is the maximum amount of time that an item can be in the cache before it is removed.
- **refreshThreshold**?: number - Default refreshThreshold in milliseconds.
- **refreshThreshold**?: number | (value:T) => number - Default refreshThreshold in milliseconds. You can also provide a function that will return the refreshThreshold based on the value.

If the remaining TTL is less than **refreshThreshold**, the system will update the value asynchronously in background.
- **refreshAllStores**?: boolean - Default false
Expand Down Expand Up @@ -319,7 +319,7 @@ See unit tests in [`test/clear.test.ts`](./test/clear.test.ts) for more informat

Wraps a function in cache. The first time the function is run, its results are stored in cache so subsequent calls retrieve from cache instead of calling the function.

If `refreshThreshold` is set and the remaining TTL is less than `refreshThreshold`, the system will update the value asynchronously. In the meantime, the system will return the old value until expiration.
If `refreshThreshold` is set and the remaining TTL is less than `refreshThreshold`, the system will update the value asynchronously. In the meantime, the system will return the old value until expiration. You can also provide a function that will return the refreshThreshold based on the value `(value:T) => number`.

```typescript
await cache.wrap('key', () => 1, 5000, 3000)
Expand Down
6 changes: 3 additions & 3 deletions packages/cache-manager/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export type Cache = {
key: string,
fnc: () => T | Promise<T>,
ttl?: number | ((value: T) => number),
refreshThreshold?: number
refreshThreshold?: number | ((value: T) => number)
) => Promise<T>;
on: <E extends keyof Events>(
event: E,
Expand Down Expand Up @@ -252,7 +252,7 @@ export const createCache = (options?: CreateCacheOptions): Cache => {
key: string,
fnc: () => T | Promise<T>,
ttl?: number | ((value: T) => number),
refreshThreshold?: number,
refreshThreshold?: number | ((value: T) => number),
): Promise<T> => coalesceAsync(`${_cacheId}::${key}`, async () => {
let value: T | undefined;
let i = 0;
Expand Down Expand Up @@ -281,7 +281,7 @@ export const createCache = (options?: CreateCacheOptions): Cache => {
return result;
}

const shouldRefresh = lt(remainingTtl, refreshThreshold ?? options?.refreshThreshold);
const shouldRefresh = lt(remainingTtl, runIfFn(refreshThreshold, value) ?? options?.refreshThreshold);

if (shouldRefresh) {
coalesceAsync(`+++${_cacheId}__${key}`, fnc)
Expand Down
19 changes: 19 additions & 0 deletions packages/cache-manager/test/wrap.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,25 @@ describe('wrap', () => {
expect(await cache.wrap(data.key, async () => 5, undefined, 500)).toEqual(4);
});

it('should allow refreshThreshold function on wrap function', async () => {
const config = {ttl: (v: number) => v * 1000, refreshThreshold: (v: number) => v * 500};

// 1st call should be cached
expect(await cache.wrap(data.key, async () => 1, config.ttl, config.refreshThreshold)).toEqual(1);
await sleep(501);
// Background refresh, but stale value returned
expect(await cache.wrap(data.key, async () => 2, config.ttl, config.refreshThreshold)).toEqual(1);
// New value in cache
expect(await cache.wrap(data.key, async () => 2, config.ttl, config.refreshThreshold)).toEqual(2);
await sleep(1001);
// No background refresh with the new override params
expect(await cache.wrap(data.key, async () => 3, undefined, 500)).toEqual(2);
await sleep(500);
// Background refresh, but stale value returned
expect(await cache.wrap(data.key, async () => 4, undefined, 500)).toEqual(2);
expect(await cache.wrap(data.key, async () => 5, undefined, 500)).toEqual(4);
});

it('should support nested calls of other caches - no mutual state', async () => {
const getValueA = vi.fn(() => 'A');
const getValueB = vi.fn(() => 'B');
Expand Down

0 comments on commit 6d1fd20

Please sign in to comment.