Skip to content

Commit

Permalink
Add refresh method to handle invalidation (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ben Clark authored Jan 10, 2020
1 parent 2468098 commit e8dffb5
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 4 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,8 @@
"**/.eslintcache": true,
"**/.cache": true,
"**/.fuse_hidden*": true
},
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
}
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ const myObjectCache = new LeprechaunCache({
onBackgroundError: e => { console.error(e); }
})

const myObject = myObjectCache.get('object-id') //get the object with key 'object-id'. If it doesn't exist, onMiss will be called, and the data will be stored in the cache with a soft TTL of 1000ms
const myObject = await myObjectCache.get('object-id') //get the object with key 'object-id'. If it doesn't exist, onMiss will be called, and the data will be stored in the cache with a soft TTL of 1000ms

const myObject = await myObjectCache.refresh('object-id') //Force refresh (calls the onMiss handler and updates the cache) and return the result

await myObjectCache.clear('object-id') //Remove the item from the cache
```

## Constructor Options
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@acuris/leprechaun-cache",
"version": "0.0.6",
"version": "0.0.7",
"private": false,
"description": "Caching library that supports double checked caching and stale returns to avoid stampede and slow responses",
"keywords": [
Expand Down
4 changes: 4 additions & 0 deletions src/leprechaun-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ export class LeprechaunCache<T extends Cacheable = Cacheable> {
return promise
}

public async refresh(key: string): Promise<T> {
return this.updateCache(key, this.softTtlMs, true)
}

private async doGet(key: string, ttl: number): Promise<T> {
const result = await this.cacheStore.get(this.keyPrefix + key)
if (!result) {
Expand Down
28 changes: 28 additions & 0 deletions test/integration/leprechaun-cache-redis.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ describe('Leprechaun Cache (integration)', () => {
const results2 = await cache.get(key)
expect(results2).to.deep.equal(data2)
})

it('should save and return undefined and null and false correctly', async () => {
const onMissStub = sandbox.stub()
onMissStub.withArgs('key-undefined').resolves(undefined)
Expand Down Expand Up @@ -263,4 +264,31 @@ describe('Leprechaun Cache (integration)', () => {
expect(result5).to.equal(0)
expect(await cache.get('key-zero')).to.equal(0)
})

it('should refresh the cache when refresh is called when not yet expired', async () => {
const onMissStub = sandbox.stub()
const res1 = { res: 1 }
const res2 = { res: 2 }
onMissStub.onCall(0).resolves(res1)
onMissStub.onCall(1).resolves(res2)

const cache = new LeprechaunCache({
softTtlMs: 10000,
hardTtlMs: 10000,
waitForUnlockMs: 1000,
spinMs: 50,
lockTtlMs: 1000,
cacheStore,
returnStale: true,
onMiss: onMissStub
})

const result1 = await cache.get('key')
expect(result1).to.deep.equal(res1)
await delay(10)

await cache.refresh('key')
const result2 = await cache.get('key')
expect(result2).to.deep.equal(res2)
})
})
26 changes: 26 additions & 0 deletions test/unit/leprechaun-cache.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,4 +274,30 @@ describe('Leprechaun Cache', () => {

expect(await memoryCacheStore.get('prefix-key')).to.not.be.null
})

it('should refresh the cache when refresh is called when not yet expired', async () => {
const onMissStub = sandbox.stub()
const res1 = { res: 1 }
const res2 = { res: 2 }
onMissStub.onCall(0).resolves(res1)
onMissStub.onCall(1).resolves(res2)

const cache = new LeprechaunCache({
softTtlMs: 10000,
hardTtlMs: 10000,
waitForUnlockMs: 1000,
spinMs: 50,
lockTtlMs: 1000,
cacheStore: memoryCacheStore,
returnStale: true,
onMiss: onMissStub
})

const result1 = await cache.get('key')
expect(result1).to.deep.equal(res1)

await cache.refresh('key')
const result2 = await cache.get('key')
expect(result2).to.deep.equal(res2)
})
})

0 comments on commit e8dffb5

Please sign in to comment.