-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for Redis and Memcached with ttls (#1191)
* Refactored caching connectors into their own packages - apollo-server-caching (exports interface for KeyValueCache) - apollo-server-caching-memcached - apollo-server-caching-redis One issue now is that there is duplication of mocks and test code in each of the packages. It would be better if we had centralized integration tests for all cache connectors, community contributed or otherwise. * export test suite for cache connectors from `apollo-server-caching` * fixed tsconfig.json * added @types
- Loading branch information
1 parent
7496eb0
commit 43627ec
Showing
21 changed files
with
382 additions
and
3 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
.idea |
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,6 @@ | ||
* | ||
!src/**/* | ||
!dist/**/* | ||
dist/**/*.test.* | ||
!package.json | ||
!README.md |
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,24 @@ | ||
{ | ||
"name": "apollo-server-caching", | ||
"version": "2.0.0-rc.0", | ||
"author": "opensource@apollographql.com", | ||
"license": "MIT", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/apollographql/apollo-server/tree/master/packages/apollo-server-caching" | ||
}, | ||
"homepage": "https://github.com/apollographql/apollo-server#readme", | ||
"bugs": { | ||
"url": "https://github.com/apollographql/apollo-server/issues" | ||
}, | ||
"scripts": { | ||
"clean": "rm -rf lib", | ||
"compile": "tsc", | ||
"prepublish": "npm run clean && npm run compile" | ||
}, | ||
"main": "dist/index.js", | ||
"types": "dist/index.d.ts", | ||
"engines": { | ||
"node": ">=6" | ||
} | ||
} |
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,4 @@ | ||
export interface KeyValueCache { | ||
get(key: string): Promise<string | undefined>; | ||
set(key: string, value: string, options?: { ttl?: number }): Promise<void>; | ||
} |
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,32 @@ | ||
const RealDate = global.Date; | ||
|
||
export function mockDate() { | ||
global.Date = new Proxy(RealDate, handler); | ||
} | ||
|
||
export function unmockDate() { | ||
global.Date = RealDate; | ||
} | ||
|
||
let now = Date.now(); | ||
|
||
export function advanceTimeBy(ms: number) { | ||
now += ms; | ||
} | ||
|
||
const handler = { | ||
construct(target, args) { | ||
if (args.length === 0) { | ||
return new Date(now); | ||
} else { | ||
return new target(...args); | ||
} | ||
}, | ||
get(target, propKey) { | ||
if (propKey === 'now') { | ||
return () => now; | ||
} else { | ||
return target[propKey]; | ||
} | ||
}, | ||
}; |
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,2 @@ | ||
export { KeyValueCache } from './KeyValueCache'; | ||
export { testKeyValueCache } from './tests'; |
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,40 @@ | ||
import { advanceTimeBy, mockDate, unmockDate } from './__mocks__/date'; | ||
|
||
export function testKeyValueCache(keyValueCache) { | ||
describe('KeyValueCache Test Suite', () => { | ||
beforeAll(() => { | ||
mockDate(); | ||
jest.useFakeTimers(); | ||
}); | ||
|
||
beforeEach(() => { | ||
keyValueCache.flush(); | ||
}); | ||
|
||
afterAll(() => { | ||
unmockDate(); | ||
keyValueCache.close(); | ||
}); | ||
|
||
it('can do a basic get and set', async () => { | ||
await keyValueCache.set('hello', 'world'); | ||
expect(await keyValueCache.get('hello')).toBe('world'); | ||
expect(await keyValueCache.get('missing')).not.toBeDefined(); | ||
}); | ||
|
||
it('is able to expire keys based on ttl', async () => { | ||
await keyValueCache.set('short', 's', { ttl: 1 }); | ||
await keyValueCache.set('long', 'l', { ttl: 5 }); | ||
expect(await keyValueCache.get('short')).toBe('s'); | ||
expect(await keyValueCache.get('long')).toBe('l'); | ||
advanceTimeBy(1500); | ||
jest.advanceTimersByTime(1500); | ||
expect(await keyValueCache.get('short')).not.toBeDefined(); | ||
expect(await keyValueCache.get('long')).toBe('l'); | ||
advanceTimeBy(4000); | ||
jest.advanceTimersByTime(4000); | ||
expect(await keyValueCache.get('short')).not.toBeDefined(); | ||
expect(await keyValueCache.get('long')).not.toBeDefined(); | ||
}); | ||
}); | ||
} |
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,16 @@ | ||
{ | ||
"extends": "../../tsconfig", | ||
"compilerOptions": { | ||
"rootDir": "./src", | ||
"outDir": "./dist", | ||
"removeComments": true, | ||
"strict": true, | ||
"noImplicitReturns": true, | ||
"noFallthroughCasesInSwitch": true, | ||
"noUnusedParameters": true, | ||
"noUnusedLocals": true, | ||
"types": ["node", "jest"] | ||
}, | ||
"include": ["src/**/*"], | ||
"exclude": ["node_modules", "**/__tests__/*", "**/__mocks__/*"] | ||
} |
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 @@ | ||
.idea |
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,6 @@ | ||
* | ||
!src/**/* | ||
!dist/**/* | ||
dist/**/*.test.* | ||
!package.json | ||
!README.md |
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,7 @@ | ||
// use mock implementations for underlying databases | ||
jest.mock('memcached', () => require('memcached-mock')); | ||
|
||
import MemcachedKeyValueCache from '../src/index'; | ||
import { testKeyValueCache } from 'apollo-server-caching'; | ||
|
||
testKeyValueCache(new MemcachedKeyValueCache('localhost')); |
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,54 @@ | ||
{ | ||
"name": "apollo-server-memcached", | ||
"version": "2.0.0-rc.0", | ||
"author": "opensource@apollographql.com", | ||
"license": "MIT", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/apollographql/apollo-server/tree/master/packages/apollo-server-memcached" | ||
}, | ||
"homepage": "https://github.com/apollographql/apollo-server#readme", | ||
"bugs": { | ||
"url": "https://github.com/apollographql/apollo-server/issues" | ||
}, | ||
"scripts": { | ||
"clean": "rm -rf lib", | ||
"compile": "tsc", | ||
"prepublish": "npm run clean && npm run compile", | ||
"test": "jest --verbose" | ||
}, | ||
"main": "dist/index.js", | ||
"types": "dist/index.d.ts", | ||
"engines": { | ||
"node": ">=6" | ||
}, | ||
"dependencies": { | ||
"apollo-server-env": "^2.0.0-rc.0", | ||
"apollo-server-caching": "^2.0.0-rc.0", | ||
"memcached": "^2.2.2" | ||
}, | ||
"devDependencies": { | ||
"@types/jest": "^23.0.0", | ||
"@types/memcached": "^2.2.5", | ||
"jest": "^23.1.0", | ||
"memcached-mock": "^0.1.0", | ||
"ts-jest": "^22.4.6" | ||
}, | ||
"jest": { | ||
"testEnvironment": "node", | ||
"transform": { | ||
"^.+\\.(ts|js)$": "ts-jest" | ||
}, | ||
"moduleFileExtensions": [ | ||
"ts", | ||
"js", | ||
"json" | ||
], | ||
"testRegex": "/__tests__/.*$", | ||
"globals": { | ||
"ts-jest": { | ||
"skipBabel": true | ||
} | ||
} | ||
} | ||
} |
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,39 @@ | ||
import { KeyValueCache } from 'apollo-server-caching'; | ||
import Memcached from 'memcached'; | ||
import { promisify } from 'util'; | ||
|
||
export default class MemcachedKeyValueCache implements KeyValueCache { | ||
readonly client; | ||
readonly defaultSetOptions = { | ||
ttl: 300, | ||
}; | ||
|
||
constructor(serverLocation: Memcached.Location, options?: Memcached.options) { | ||
this.client = new Memcached(serverLocation, options); | ||
// promisify client calls for convenience | ||
this.client.get = promisify(this.client.get).bind(this.client); | ||
this.client.set = promisify(this.client.set).bind(this.client); | ||
this.client.flush = promisify(this.client.flush).bind(this.client); | ||
} | ||
|
||
async set( | ||
key: string, | ||
data: string, | ||
options?: { ttl?: number }, | ||
): Promise<void> { | ||
const { ttl } = Object.assign({}, this.defaultSetOptions, options); | ||
await this.client.set(key, data, ttl); | ||
} | ||
|
||
async get(key: string): Promise<string | undefined> { | ||
return await this.client.get(key); | ||
} | ||
|
||
async flush(): Promise<void> { | ||
await this.client.flush(); | ||
} | ||
|
||
async close(): Promise<void> { | ||
this.client.end(); | ||
} | ||
} |
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,16 @@ | ||
{ | ||
"extends": "../../tsconfig", | ||
"compilerOptions": { | ||
"rootDir": "./src", | ||
"outDir": "./dist", | ||
"removeComments": true, | ||
"strict": true, | ||
"noImplicitReturns": true, | ||
"noFallthroughCasesInSwitch": true, | ||
"noUnusedParameters": true, | ||
"noUnusedLocals": true, | ||
"types": ["node", "jest"] | ||
}, | ||
"include": ["src/**/*"], | ||
"exclude": ["node_modules", "**/__tests__/*", "**/__mocks__/*"] | ||
} |
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 @@ | ||
.idea |
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,6 @@ | ||
* | ||
!src/**/* | ||
!dist/**/* | ||
dist/**/*.test.* | ||
!package.json | ||
!README.md |
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 @@ | ||
// use mock implementations for underlying databases | ||
jest.mock('redis', () => require('redis-mock')); | ||
jest.useFakeTimers(); // mocks out setTimeout that is used in redis-mock | ||
|
||
import RedisKeyValueCache from '../src/index'; | ||
import { testKeyValueCache } from 'apollo-server-caching'; | ||
|
||
testKeyValueCache(new RedisKeyValueCache({ host: 'localhost' })); |
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,54 @@ | ||
{ | ||
"name": "apollo-server-redis", | ||
"version": "2.0.0-rc.0", | ||
"author": "opensource@apollographql.com", | ||
"license": "MIT", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/apollographql/apollo-server/tree/master/packages/apollo-server-redis" | ||
}, | ||
"homepage": "https://github.com/apollographql/apollo-server#readme", | ||
"bugs": { | ||
"url": "https://github.com/apollographql/apollo-server/issues" | ||
}, | ||
"scripts": { | ||
"clean": "rm -rf lib", | ||
"compile": "tsc", | ||
"prepublish": "npm run clean && npm run compile", | ||
"test": "jest --verbose" | ||
}, | ||
"main": "dist/index.js", | ||
"types": "dist/index.d.ts", | ||
"engines": { | ||
"node": ">=6" | ||
}, | ||
"dependencies": { | ||
"apollo-server-caching": "^2.0.0-rc.0", | ||
"apollo-server-env": "^2.0.0-rc.0", | ||
"redis": "^2.8.0" | ||
}, | ||
"devDependencies": { | ||
"@types/jest": "^23.0.0", | ||
"@types/redis": "^2.8.6", | ||
"jest": "^23.1.0", | ||
"redis-mock": "^0.27.0", | ||
"ts-jest": "^22.4.6" | ||
}, | ||
"jest": { | ||
"testEnvironment": "node", | ||
"transform": { | ||
"^.+\\.(ts|js)$": "ts-jest" | ||
}, | ||
"moduleFileExtensions": [ | ||
"ts", | ||
"js", | ||
"json" | ||
], | ||
"testRegex": "/__tests__/.*$", | ||
"globals": { | ||
"ts-jest": { | ||
"skipBabel": true | ||
} | ||
} | ||
} | ||
} |
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,46 @@ | ||
import { KeyValueCache } from 'apollo-server-caching'; | ||
import Redis from 'redis'; | ||
import { promisify } from 'util'; | ||
|
||
export default class RedisKeyValueCache implements KeyValueCache { | ||
readonly client; | ||
readonly defaultSetOptions = { | ||
ttl: 300, | ||
}; | ||
|
||
constructor(options: Redis.ClientOpts) { | ||
this.client = Redis.createClient(options); | ||
// promisify client calls for convenience | ||
this.client.get = promisify(this.client.get).bind(this.client); | ||
this.client.set = promisify(this.client.set).bind(this.client); | ||
this.client.flushdb = promisify(this.client.flushdb).bind(this.client); | ||
this.client.quit = promisify(this.client.quit).bind(this.client); | ||
} | ||
|
||
async set( | ||
key: string, | ||
data: string, | ||
options?: { ttl?: number }, | ||
): Promise<void> { | ||
const { ttl } = Object.assign({}, this.defaultSetOptions, options); | ||
await this.client.set(key, data, 'EX', ttl); | ||
} | ||
|
||
async get(key: string): Promise<string | undefined> { | ||
const reply = await this.client.get(key); | ||
// reply is null if key is not found | ||
if (reply !== null) { | ||
return reply; | ||
} | ||
return; | ||
} | ||
|
||
async flush(): Promise<void> { | ||
await this.client.flushdb(); | ||
} | ||
|
||
async close(): Promise<void> { | ||
await this.client.quit(); | ||
return; | ||
} | ||
} |
Oops, something went wrong.