@adaptivestone/framework 3.0.20 → 3.0.21
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/.env.example +3 -0
- package/CHANGELOG.md +3 -2
- package/commands/GetOpenApiJson.js +1 -1
- package/config/redis.js +1 -0
- package/helpers/redis/clearNamespace.js +14 -0
- package/package.json +2 -2
- package/services/cache/Cache.js +14 -6
- package/services/http/middleware/RateLimiter.js +17 -5
- package/tests/setup.js +26 -0
package/.env.example
CHANGED
package/CHANGELOG.md
CHANGED
package/config/redis.js
CHANGED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
async function clearNamespace(redisClient, namespace) {
|
|
2
|
+
const deletedKeys = [];
|
|
3
|
+
|
|
4
|
+
const keys = await redisClient.sendCommand(['keys', `*${namespace}*`]);
|
|
5
|
+
|
|
6
|
+
if (keys && keys.length > 0) {
|
|
7
|
+
for (const key of keys) {
|
|
8
|
+
deletedKeys.push(redisClient.sendCommand(['del', key]));
|
|
9
|
+
}
|
|
10
|
+
await Promise.all(deletedKeys);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
module.exports = clearNamespace;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adaptivestone/framework",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.21",
|
|
4
4
|
"description": "Adaptive stone node js framework",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"engines": {
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"prettier": "^2.3.2",
|
|
48
48
|
"pug": "^3.0.2",
|
|
49
49
|
"rate-limiter-flexible": "^2.2.4",
|
|
50
|
-
"redis": "^3.1
|
|
50
|
+
"redis": "^4.3.1",
|
|
51
51
|
"winston": "^3.3.3",
|
|
52
52
|
"winston-transport-sentry-node": "^2.0.0",
|
|
53
53
|
"yup": "^0.32.9"
|
package/services/cache/Cache.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const redis = require('redis');
|
|
2
|
-
const { promisify } = require('util');
|
|
3
2
|
const Base = require('../../modules/Base');
|
|
4
3
|
|
|
5
4
|
class Cache extends Base {
|
|
@@ -10,7 +9,12 @@ class Cache extends Base {
|
|
|
10
9
|
// we should support multiple cashe same time
|
|
11
10
|
super(app);
|
|
12
11
|
const conf = this.app.getConfig('redis');
|
|
13
|
-
this.redisClient = redis.createClient(
|
|
12
|
+
this.redisClient = redis.createClient({
|
|
13
|
+
url: conf.url,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
this.redisNamespace = conf.namespace;
|
|
17
|
+
|
|
14
18
|
this.redisClient.on('error', (error, b, c) => {
|
|
15
19
|
this.logger.error(error, b, c);
|
|
16
20
|
});
|
|
@@ -20,11 +24,15 @@ class Cache extends Base {
|
|
|
20
24
|
this.app.events.on('shutdown', () => {
|
|
21
25
|
this.redisClient.quit();
|
|
22
26
|
});
|
|
23
|
-
|
|
27
|
+
|
|
24
28
|
this.promiseMapping = new Map();
|
|
25
29
|
}
|
|
26
30
|
|
|
27
|
-
async getSetValue(
|
|
31
|
+
async getSetValue(keyValue, onNotFound, storeTime = 60 * 5) {
|
|
32
|
+
if (!this.redisClient.isOpen) {
|
|
33
|
+
await this.redisClient.connect();
|
|
34
|
+
}
|
|
35
|
+
const key = `${this.redisNamespace}-${keyValue}`;
|
|
28
36
|
// 5 mins default
|
|
29
37
|
let resolve = null;
|
|
30
38
|
if (this.promiseMapping.has(key)) {
|
|
@@ -38,11 +46,11 @@ class Cache extends Base {
|
|
|
38
46
|
}),
|
|
39
47
|
);
|
|
40
48
|
|
|
41
|
-
let result = await this.
|
|
49
|
+
let result = await this.redisClient.get(key);
|
|
42
50
|
if (!result) {
|
|
43
51
|
this.logger.verbose(`getSetValueFromCache not found for key ${key}`);
|
|
44
52
|
result = await onNotFound();
|
|
45
|
-
this.redisClient.
|
|
53
|
+
this.redisClient.setEx(key, storeTime, JSON.stringify(result));
|
|
46
54
|
} else {
|
|
47
55
|
this.logger.verbose(
|
|
48
56
|
`getSetValueFromCache FROM CACHE key ${key}, value ${result}`,
|
|
@@ -16,9 +16,10 @@ class RateLimiter extends AbstractMiddleware {
|
|
|
16
16
|
|
|
17
17
|
constructor(app, params) {
|
|
18
18
|
super(app, params);
|
|
19
|
+
const routeParams = params;
|
|
19
20
|
const limiterOptions = this.app.getConfig('rateLimiter');
|
|
20
|
-
this.finalOptions = merge(limiterOptions, params);
|
|
21
21
|
|
|
22
|
+
this.finalOptions = merge(limiterOptions, routeParams);
|
|
22
23
|
this.limiter = null;
|
|
23
24
|
|
|
24
25
|
switch (this.finalOptions.driver) {
|
|
@@ -47,7 +48,16 @@ class RateLimiter extends AbstractMiddleware {
|
|
|
47
48
|
|
|
48
49
|
initRedisLimiter() {
|
|
49
50
|
const redisConfig = this.app.getConfig('redis');
|
|
50
|
-
const redisClient = redis.createClient(
|
|
51
|
+
const redisClient = redis.createClient({
|
|
52
|
+
url: redisConfig.url,
|
|
53
|
+
legacyMode: true,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// TODO: change it
|
|
57
|
+
(async () => {
|
|
58
|
+
await redisClient.connect();
|
|
59
|
+
})();
|
|
60
|
+
|
|
51
61
|
redisClient.on('error', (error, b, c) => {
|
|
52
62
|
this.logger.error(error, b, c);
|
|
53
63
|
});
|
|
@@ -55,8 +65,8 @@ class RateLimiter extends AbstractMiddleware {
|
|
|
55
65
|
this.logger.info('Redis connection success');
|
|
56
66
|
});
|
|
57
67
|
|
|
58
|
-
this.app.events.on('shutdown', () => {
|
|
59
|
-
redisClient.
|
|
68
|
+
this.app.events.on('shutdown', async () => {
|
|
69
|
+
await redisClient.disconnect();
|
|
60
70
|
});
|
|
61
71
|
|
|
62
72
|
return new RateLimiterRedis({
|
|
@@ -100,7 +110,9 @@ class RateLimiter extends AbstractMiddleware {
|
|
|
100
110
|
);
|
|
101
111
|
}
|
|
102
112
|
|
|
103
|
-
const
|
|
113
|
+
const { namespace } = this.app.getConfig('redis');
|
|
114
|
+
|
|
115
|
+
const consumeKey = `${namespace}-${this.gerenateConsumeKey(req)}`;
|
|
104
116
|
|
|
105
117
|
const consumeResult = await this.limiter
|
|
106
118
|
.consume(consumeKey, this.finalOptions.consumePoints)
|
package/tests/setup.js
CHANGED
|
@@ -4,8 +4,11 @@ const mongoose = require('mongoose');
|
|
|
4
4
|
|
|
5
5
|
let mongoMemoryServerInstance;
|
|
6
6
|
const path = require('path');
|
|
7
|
+
const redis = require('redis');
|
|
7
8
|
const Server = require('../server');
|
|
8
9
|
|
|
10
|
+
const clearRadisNamespace = require('../helpers/redis/clearNamespace');
|
|
11
|
+
|
|
9
12
|
jest.setTimeout(1000000);
|
|
10
13
|
beforeAll(async () => {
|
|
11
14
|
mongoMemoryServerInstance = await MongoMemoryReplSet.create({
|
|
@@ -63,6 +66,27 @@ beforeAll(async () => {
|
|
|
63
66
|
}
|
|
64
67
|
await global.server.startServer();
|
|
65
68
|
});
|
|
69
|
+
|
|
70
|
+
beforeEach(() => {
|
|
71
|
+
if (global.server) {
|
|
72
|
+
const key = `test-${Math.random().toString(36).substring(7)}`;
|
|
73
|
+
global.server.app.updateConfig('redis', {
|
|
74
|
+
namespace: key,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
afterEach(async () => {
|
|
80
|
+
if (global.server) {
|
|
81
|
+
const { url, namespace } = global.server.getConfig('redis');
|
|
82
|
+
const redisClient = redis.createClient({ url });
|
|
83
|
+
|
|
84
|
+
await redisClient.connect();
|
|
85
|
+
await clearRadisNamespace(redisClient, namespace);
|
|
86
|
+
await redisClient.disconnect();
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
66
90
|
afterAll(async () => {
|
|
67
91
|
if (global.server) {
|
|
68
92
|
global.server.app.httpServer.shutdown();
|
|
@@ -72,7 +96,9 @@ afterAll(async () => {
|
|
|
72
96
|
if (typeof global.testSetup.afterAll === 'function') {
|
|
73
97
|
await global.testSetup.afterAll();
|
|
74
98
|
}
|
|
99
|
+
|
|
75
100
|
await mongoose.disconnect();
|
|
76
101
|
await mongoMemoryServerInstance.stop();
|
|
102
|
+
|
|
77
103
|
// }, 2000);
|
|
78
104
|
});
|