-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
When the SDK retrieves data from the EdgeKV, it does so using a single sub-request per call to `variation`, `variationDetail`, or `allFlagsState`. The problem is that Akamai imposes a limit of 4 sub-requests per handler event. If a customer evaluates more than 4 distinct flags during the handling of a single event, subsequent flag lookups would fail. To combat this, we now cache the flag values for a specified amount of time. --------- Co-authored-by: Ryan Lamb <[email protected]>
- Loading branch information
1 parent
9f3e3b6
commit 4f961dd
Showing
6 changed files
with
197 additions
and
13 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
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
101 changes: 101 additions & 0 deletions
101
packages/shared/akamai-edgeworker-sdk/__tests__/featureStore/cacheableStore.test.ts
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,101 @@ | ||
import { EdgeProvider } from '../../src/featureStore'; | ||
import CacheableStoreProvider from '../../src/featureStore/cacheableStoreProvider'; | ||
import * as testData from '../testData.json'; | ||
|
||
describe('given a mock edge provider with test data', () => { | ||
const mockEdgeProvider: EdgeProvider = { | ||
get: jest.fn(), | ||
}; | ||
const mockGet = mockEdgeProvider.get as jest.Mock; | ||
|
||
beforeEach(() => { | ||
jest.useFakeTimers(); | ||
mockGet.mockImplementation(() => Promise.resolve(JSON.stringify(testData))); | ||
}); | ||
|
||
afterEach(() => { | ||
jest.resetAllMocks(); | ||
}); | ||
|
||
describe('without cache TTL', () => { | ||
it('caches initial request', async () => { | ||
const cacheProvider = new CacheableStoreProvider(mockEdgeProvider, 'rootKey'); | ||
await cacheProvider.get('rootKey'); | ||
await cacheProvider.get('rootKey'); | ||
expect(mockGet).toHaveBeenCalledTimes(1); | ||
}); | ||
|
||
it('can force a refresh', async () => { | ||
const cacheProvider = new CacheableStoreProvider(mockEdgeProvider, 'rootKey'); | ||
await cacheProvider.get('rootKey'); | ||
await cacheProvider.get('rootKey'); | ||
expect(mockGet).toHaveBeenCalledTimes(1); | ||
|
||
await cacheProvider.prefetchPayloadFromOriginStore(); | ||
await cacheProvider.get('rootKey'); | ||
expect(mockGet).toHaveBeenCalledTimes(2); | ||
}); | ||
}); | ||
|
||
describe('with infinite cache ttl', () => { | ||
it('caches initial request', async () => { | ||
const cacheProvider = new CacheableStoreProvider(mockEdgeProvider, 'rootKey', 0); | ||
await cacheProvider.get('rootKey'); | ||
await cacheProvider.get('rootKey'); | ||
expect(mockGet).toHaveBeenCalledTimes(1); | ||
}); | ||
|
||
it('does not reset on prefetch', async () => { | ||
const cacheProvider = new CacheableStoreProvider(mockEdgeProvider, 'rootKey', 0); | ||
await cacheProvider.get('rootKey'); | ||
await cacheProvider.get('rootKey'); | ||
expect(mockGet).toHaveBeenCalledTimes(1); | ||
|
||
await cacheProvider.prefetchPayloadFromOriginStore(); | ||
await cacheProvider.get('rootKey'); | ||
expect(mockGet).toHaveBeenCalledTimes(1); | ||
}); | ||
}); | ||
|
||
describe('with finite cache ttl', () => { | ||
it('caches initial request', async () => { | ||
const cacheProvider = new CacheableStoreProvider(mockEdgeProvider, 'rootKey', 50); | ||
await cacheProvider.get('rootKey'); | ||
await cacheProvider.get('rootKey'); | ||
expect(mockGet).toHaveBeenCalledTimes(1); | ||
}); | ||
|
||
it('caches expires after duration', async () => { | ||
jest.spyOn(Date, 'now').mockImplementation(() => 0); | ||
const cacheProvider = new CacheableStoreProvider(mockEdgeProvider, 'rootKey', 50); | ||
await cacheProvider.get('rootKey'); | ||
await cacheProvider.get('rootKey'); | ||
expect(mockGet).toHaveBeenCalledTimes(1); | ||
|
||
jest.spyOn(Date, 'now').mockImplementation(() => 20); | ||
await cacheProvider.get('rootKey'); | ||
expect(mockGet).toHaveBeenCalledTimes(1); | ||
|
||
jest.spyOn(Date, 'now').mockImplementation(() => 50); | ||
await cacheProvider.get('rootKey'); | ||
expect(mockGet).toHaveBeenCalledTimes(2); | ||
}); | ||
|
||
it('prefetch respects cache TTL', async () => { | ||
jest.spyOn(Date, 'now').mockImplementation(() => 0); | ||
const cacheProvider = new CacheableStoreProvider(mockEdgeProvider, 'rootKey', 50); | ||
await cacheProvider.get('rootKey'); | ||
await cacheProvider.get('rootKey'); | ||
expect(mockGet).toHaveBeenCalledTimes(1); | ||
|
||
await cacheProvider.prefetchPayloadFromOriginStore(); | ||
await cacheProvider.get('rootKey'); | ||
expect(mockGet).toHaveBeenCalledTimes(1); | ||
|
||
jest.spyOn(Date, 'now').mockImplementation(() => 50); | ||
await cacheProvider.prefetchPayloadFromOriginStore(); | ||
await cacheProvider.get('rootKey'); | ||
expect(mockGet).toHaveBeenCalledTimes(2); | ||
}); | ||
}); | ||
}); |
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