exframe-cache-manager 1.3.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +2 -16
- package/Dockerfile +4 -4
- package/docker-compose.yml +1 -0
- package/index.js +184 -208
- package/package.json +14 -14
- package/test/.eslintrc.json +3 -0
- package/test/cacheManager.test.js +1 -2
package/.eslintrc.json
CHANGED
|
@@ -1,17 +1,3 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
|
|
4
|
-
"node": true
|
|
5
|
-
},
|
|
6
|
-
"extends": "airbnb-base",
|
|
7
|
-
"rules": {
|
|
8
|
-
"comma-dangle": ["error", "never"],
|
|
9
|
-
"strict": ["off", "global"] ,
|
|
10
|
-
"consistent-return": "off",
|
|
11
|
-
"linebreak-style": ["error", "windows"],
|
|
12
|
-
"max-len": ["error", 200],
|
|
13
|
-
"no-param-reassign": ["error", { "props": false }],
|
|
14
|
-
"no-underscore-dangle": "off",
|
|
15
|
-
"arrow-parens": "off"
|
|
16
|
-
}
|
|
17
|
-
}
|
|
2
|
+
"extends": "exzeo/base"
|
|
3
|
+
}
|
package/Dockerfile
CHANGED
|
@@ -7,11 +7,11 @@ RUN apk update && \
|
|
|
7
7
|
addgroup -S docker && adduser -S -G docker docker
|
|
8
8
|
|
|
9
9
|
COPY ./package.json /app/package.json
|
|
10
|
-
WORKDIR /app
|
|
11
|
-
RUN npm install && \
|
|
12
|
-
npm cache clean --force
|
|
13
|
-
|
|
14
10
|
COPY . /app
|
|
15
11
|
|
|
12
|
+
WORKDIR /app
|
|
13
|
+
RUN yarn install
|
|
14
|
+
RUN npm run peers
|
|
15
|
+
|
|
16
16
|
# Override the command, to run the test instead of the application
|
|
17
17
|
CMD ["npm", "run", "unit-test"]
|
package/docker-compose.yml
CHANGED
package/index.js
CHANGED
|
@@ -1,208 +1,184 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const CacheManager = require('cache-manager');
|
|
4
|
-
const RedisStore = require('cache-manager-redis');
|
|
5
|
-
const util = require('util');
|
|
6
|
-
const { lazyInstrument } = require('exframe-metrics');
|
|
7
|
-
|
|
8
|
-
const db = 0;
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Cache manager for storing stuff.
|
|
12
|
-
* Options is required to pass the redis location
|
|
13
|
-
* @param {Options} options
|
|
14
|
-
*/
|
|
15
|
-
function cachemanager(options) {
|
|
16
|
-
if (options.url) {
|
|
17
|
-
options.host = undefined;
|
|
18
|
-
options.port = undefined;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const redisCache = CacheManager.caching({
|
|
22
|
-
store: RedisStore,
|
|
23
|
-
ttl: 600,
|
|
24
|
-
db,
|
|
25
|
-
...options
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
// @ts-ignore
|
|
29
|
-
const redisStore = redisCache.store;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
*
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
*
|
|
48
|
-
* @
|
|
49
|
-
* @param {
|
|
50
|
-
* @param {
|
|
51
|
-
* @
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
*
|
|
64
|
-
* @param {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
*
|
|
73
|
-
* @param {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
*
|
|
82
|
-
* @param {
|
|
83
|
-
* @
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
*
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
return instance;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
module.exports = {
|
|
191
|
-
create: cachemanager
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* @typedef {RedisCacheManagerOptions & { store?: any, ttl?: number, db?: number }} Options
|
|
196
|
-
*/
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* @typedef {{ db?: number, url?: string, host?: string, port?: string }} RedisCacheManagerOptions
|
|
200
|
-
*/
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* @typedef {{ [key: string]: any, log: { [key: string]: LogLevel, info: LogLevel, error: LogLevel } }} Context
|
|
204
|
-
*/
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* @typedef {(message: string, meta: { [key: string]: any }) => void} LogLevel
|
|
208
|
-
*/
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const CacheManager = require('cache-manager');
|
|
4
|
+
const RedisStore = require('cache-manager-redis-store');
|
|
5
|
+
const util = require('util');
|
|
6
|
+
const { lazyInstrument } = require('exframe-metrics');
|
|
7
|
+
|
|
8
|
+
const db = 0;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Cache manager for storing stuff.
|
|
12
|
+
* Options is required to pass the redis location
|
|
13
|
+
* @param {Options} options
|
|
14
|
+
*/
|
|
15
|
+
function cachemanager(options) {
|
|
16
|
+
if (options.url) {
|
|
17
|
+
options.host = undefined;
|
|
18
|
+
options.port = undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const redisCache = CacheManager.caching({
|
|
22
|
+
store: RedisStore,
|
|
23
|
+
ttl: 600,
|
|
24
|
+
db,
|
|
25
|
+
...options
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// @ts-ignore
|
|
29
|
+
const redisStore = redisCache.store;
|
|
30
|
+
const redisClient = redisStore.getClient();
|
|
31
|
+
redisClient.setMaxListeners(0);
|
|
32
|
+
|
|
33
|
+
const instance = {
|
|
34
|
+
get cacheStorePool() {
|
|
35
|
+
return redisClient;
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
*
|
|
40
|
+
* @param {string} key
|
|
41
|
+
*/
|
|
42
|
+
getItem(key) {
|
|
43
|
+
return redisCache.get(key);
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
*
|
|
48
|
+
* @template T
|
|
49
|
+
* @param {string} key
|
|
50
|
+
* @param {T} value
|
|
51
|
+
* @param {number} [ttl]
|
|
52
|
+
* @returns {Promise<T>}
|
|
53
|
+
*/
|
|
54
|
+
async setItem(key, value, ttl) {
|
|
55
|
+
await redisCache.set(key, value, {
|
|
56
|
+
ttl: ttl || Number(process.env.REDIS_CACHE_TTL)
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return value;
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
*
|
|
64
|
+
* @param {string} key
|
|
65
|
+
* @param {any} value
|
|
66
|
+
*/
|
|
67
|
+
addSetItem(key, value) {
|
|
68
|
+
return this.processRedisCommands(client => client.sadd(key, value));
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
*
|
|
73
|
+
* @param {string} key
|
|
74
|
+
* @param {any} value
|
|
75
|
+
*/
|
|
76
|
+
removeSetItem(key, value) {
|
|
77
|
+
return this.processRedisCommands(client => client.srem(key, value));
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
*
|
|
82
|
+
* @param {string} key
|
|
83
|
+
* @param {any} value
|
|
84
|
+
* @returns {Promise<Boolean>}
|
|
85
|
+
*/
|
|
86
|
+
isSetMember(key, value) {
|
|
87
|
+
return this.processRedisCommands(async client => new Promise((res, rej) => {
|
|
88
|
+
client.sismember(key, value, (ex, result) => {
|
|
89
|
+
if (ex) return rej(ex);
|
|
90
|
+
res(result === 1);
|
|
91
|
+
});
|
|
92
|
+
}));
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @returns {Promise<true>}
|
|
97
|
+
*/
|
|
98
|
+
async healthCheck() {
|
|
99
|
+
return this.processRedisCommands(client => client && client.server_info.loading === '0');
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
close() {
|
|
103
|
+
return new Promise(res => {
|
|
104
|
+
redisClient.end(true);
|
|
105
|
+
res();
|
|
106
|
+
});
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
getClient() {
|
|
110
|
+
return new Promise((resolve, reject) => {
|
|
111
|
+
if (redisClient.connected) {
|
|
112
|
+
return resolve(redisClient);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
redisClient.on('ready', () => resolve(redisClient));
|
|
116
|
+
redisClient.on('error', (e) => reject(e));
|
|
117
|
+
});
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
*
|
|
122
|
+
* @param {(client: any) => any} fn
|
|
123
|
+
*/
|
|
124
|
+
async processRedisCommands(fn) {
|
|
125
|
+
const client = await this.getClient();
|
|
126
|
+
const result = await fn(client);
|
|
127
|
+
|
|
128
|
+
return result;
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
*
|
|
133
|
+
* @param {Context} context
|
|
134
|
+
* @param {string | RegExp} pattern
|
|
135
|
+
*/
|
|
136
|
+
flushCache(context, pattern) {
|
|
137
|
+
return this.processRedisCommands(async (client) => {
|
|
138
|
+
const scanAsync = util.promisify(client.scan).bind(client);
|
|
139
|
+
const delAsync = util.promisify(client.del).bind(client);
|
|
140
|
+
let cursor = '0';
|
|
141
|
+
do {
|
|
142
|
+
const result = await scanAsync(cursor, 'MATCH', pattern);
|
|
143
|
+
([cursor] = result);
|
|
144
|
+
const keys = result[1];
|
|
145
|
+
context.log.info('matched keys', {
|
|
146
|
+
keys: result[1]
|
|
147
|
+
});
|
|
148
|
+
if (keys.length > 0) {
|
|
149
|
+
await delAsync(...keys);
|
|
150
|
+
}
|
|
151
|
+
} while (cursor !== '0');
|
|
152
|
+
});
|
|
153
|
+
},
|
|
154
|
+
redisClient
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
Object.keys(instance).forEach((key) => {
|
|
158
|
+
if (typeof instance[key] === 'function') {
|
|
159
|
+
instance[key] = lazyInstrument(instance[key].bind(instance), { metricPrefix: 'cache' });
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
return instance;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
module.exports = {
|
|
167
|
+
create: cachemanager
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* @typedef {RedisCacheManagerOptions & { store?: any, ttl?: number, db?: number }} Options
|
|
172
|
+
*/
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* @typedef {{ db?: number, url?: string, host?: string, port?: string }} RedisCacheManagerOptions
|
|
176
|
+
*/
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* @typedef {{ [key: string]: any, log: { [key: string]: LogLevel, info: LogLevel, error: LogLevel } }} Context
|
|
180
|
+
*/
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* @typedef {(message: string, meta: { [key: string]: any }) => void} LogLevel
|
|
184
|
+
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "exframe-cache-manager",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Managing the cache",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"config": {
|
|
@@ -11,9 +11,10 @@
|
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
13
|
"pretest": "npm-install-peers && npm run lint",
|
|
14
|
-
"lint": "
|
|
14
|
+
"lint": "eslint ./",
|
|
15
|
+
"peers": "npm-install-peers",
|
|
15
16
|
"test": "docker-compose -f docker-compose.yml up --abort-on-container-exit --exit-code-from exframe-cache-manager",
|
|
16
|
-
"unit-test": "nyc -r lcov --report-dir ./documentation/coverage -t ./documentation/coverage mocha --reporter $npm_package_config_reporter \"./test/**/*.test.js\""
|
|
17
|
+
"unit-test": "./node_modules/.bin/nyc -r lcov --report-dir ./documentation/coverage -t ./documentation/coverage mocha --exit --reporter $npm_package_config_reporter \"./test/**/*.test.js\""
|
|
17
18
|
},
|
|
18
19
|
"author": "Exzeo",
|
|
19
20
|
"license": "ISC",
|
|
@@ -24,26 +25,25 @@
|
|
|
24
25
|
},
|
|
25
26
|
"dependencies": {
|
|
26
27
|
"@types/cache-manager": "^3.4.2",
|
|
27
|
-
"@types/redis": "^2.8.32",
|
|
28
28
|
"cache-manager": "^3.6.0",
|
|
29
|
-
"cache-manager-redis": "^0.
|
|
30
|
-
"exframe-metrics": "^1.1.0"
|
|
31
|
-
"redis": "^3.1.2"
|
|
29
|
+
"cache-manager-redis-store": "^2.0.0",
|
|
30
|
+
"exframe-metrics": "^1.1.0"
|
|
32
31
|
},
|
|
33
32
|
"devDependencies": {
|
|
34
|
-
"chai": "
|
|
35
|
-
"eslint": "
|
|
36
|
-
"eslint-config-
|
|
37
|
-
"eslint-plugin-import": "
|
|
33
|
+
"chai": "*",
|
|
34
|
+
"eslint": "*",
|
|
35
|
+
"eslint-config-exzeo": "*",
|
|
36
|
+
"eslint-plugin-import": "*",
|
|
38
37
|
"mocha": "*",
|
|
39
|
-
"mocha-exzeo-reporter": "
|
|
38
|
+
"mocha-exzeo-reporter": "*",
|
|
40
39
|
"npm-install-peers": "*",
|
|
41
|
-
"nyc": "*"
|
|
40
|
+
"nyc": "*",
|
|
41
|
+
"sinon": "*"
|
|
42
42
|
},
|
|
43
43
|
"repository": {
|
|
44
44
|
"type": "git",
|
|
45
45
|
"url": "https://bitbucket.org/exzeo-usa/exframe",
|
|
46
46
|
"directory": "packages/exframe-cache-manager"
|
|
47
47
|
},
|
|
48
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "93013f9bb8a75217a24b69b7c2ad72b8baebddc7"
|
|
49
49
|
}
|
|
@@ -105,7 +105,7 @@ context('Test User Profile Middleware', () => {
|
|
|
105
105
|
const result = await app1.getItem(cacheKey);
|
|
106
106
|
expect(result).to.not.be.ok();
|
|
107
107
|
} catch (ex) {
|
|
108
|
-
expect(ex.message).to.be.equal('
|
|
108
|
+
expect(ex.message).to.be.equal('GET can\'t be processed. The connection is already closed.');
|
|
109
109
|
const metrics = prometheusClient.register.getMetricsAsArray().filter((m) => m.name.includes('close'));
|
|
110
110
|
expect(metrics).to.be.an('array').and.to.have.lengthOf.above(0);
|
|
111
111
|
}
|
|
@@ -122,7 +122,6 @@ context('Test User Profile Middleware', () => {
|
|
|
122
122
|
it('validate the cacheStorePool', () => {
|
|
123
123
|
const catchepool = app.cacheStorePool;
|
|
124
124
|
expect(app).to.not.eql(null);
|
|
125
|
-
expect(catchepool.db).to.eql(0);
|
|
126
125
|
expect(catchepool._maxListeners).to.eql(0);
|
|
127
126
|
});
|
|
128
127
|
|