@sera4/essentia 1.0.38 → 1.0.39
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/cache/index.js +188 -0
- package/health/index.js +9 -4
- package/package.json +1 -1
- package/package.tar.gz +0 -0
package/cache/index.js
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"use strict"
|
|
2
|
+
|
|
3
|
+
import { promisify } from "util";
|
|
4
|
+
|
|
5
|
+
const isEmpty = obj => [Object, Array].includes((obj || {}).constructor) && !Object.entries((obj || {})).length;
|
|
6
|
+
|
|
7
|
+
class CacheConfigError extends Error {
|
|
8
|
+
constructor(m) {
|
|
9
|
+
super(m);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/* Redis cache helper
|
|
14
|
+
* Example use: Place the following code in your project to setup redis use
|
|
15
|
+
*
|
|
16
|
+
* import { cache } from "@sera4/essentia";
|
|
17
|
+
* const cacheHelper = cache({ password: .., database: .., host: .., port: .. }, "service:"));
|
|
18
|
+
*
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
const convertRedisKeyValueToJson = (v) => {
|
|
22
|
+
return (v && v.length > 0 && v[0] !== null) ? JSON.parse(v) : null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const convertRedisHashToJson = (v) => {
|
|
26
|
+
if (v) {
|
|
27
|
+
var result = {};
|
|
28
|
+
for(var k in v) {
|
|
29
|
+
if (v.hasOwnProperty(k)) {
|
|
30
|
+
result[k] = JSON.parse(v[k]);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return result;
|
|
34
|
+
} else {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function convertJsonToRedisValue(j) {
|
|
40
|
+
var result = {};
|
|
41
|
+
for (var key in j) {
|
|
42
|
+
if (j.hasOwnProperty(key)) {
|
|
43
|
+
result[key] = JSON.stringify(j[key]);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
class Cache {
|
|
50
|
+
constructor(config, servicePrefix) {
|
|
51
|
+
if ((config == undefined) || isEmpty(config)) {
|
|
52
|
+
throw new CacheConfigError("Invalid cache configuration");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (servicePrefix == null) {
|
|
56
|
+
throw new CacheConfigError("Invalid service prefix");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (config.fake) {
|
|
60
|
+
// used in testing
|
|
61
|
+
this.redisClient = require("fakeredis").createClient("fake backend")
|
|
62
|
+
} else {
|
|
63
|
+
this.redisClient = require("redis").createClient(config);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
this.redisClient.on("error", (err) => {
|
|
67
|
+
logger.error("Cache/Redis error: ", err);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
this.servicePrefix = servicePrefix;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
ping() {
|
|
74
|
+
return this.redisClient.ping();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
properKey(key, path) {
|
|
78
|
+
let p = this.servicePrefix + key
|
|
79
|
+
if (path)
|
|
80
|
+
p += path
|
|
81
|
+
return p
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
writeHash(path, key, value) {
|
|
85
|
+
return this.redisClient.hsetAsync(properKey(key), key, value);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
writeHashBlocking(path, key, value) {
|
|
89
|
+
return this.redisClient.hset(properKey(key), key, value);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// write multiple hash keys and stringify every value
|
|
93
|
+
writeMultiHash(path, j) {
|
|
94
|
+
return this.redisClient.hmsetAsync(properKey(key), convertJsonToRedisValue(j));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
readHashKey(obj, key, autoConvert=true) {
|
|
98
|
+
var k = autoConvert;
|
|
99
|
+
|
|
100
|
+
return new Promise((resolve, reject) => {
|
|
101
|
+
this.redisClient.hget(properKey(key, obj), key, (e, r) => {
|
|
102
|
+
if (e) {
|
|
103
|
+
logger.error("Redis hmget error:", e);
|
|
104
|
+
reject(e);
|
|
105
|
+
} else {
|
|
106
|
+
resolve(k ? convertRedisKeyValueToJson(r) : r);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
readHash(path) {
|
|
113
|
+
return new Promise((resolve, reject) => {
|
|
114
|
+
this.redisClient.hgetall(properKey(key, path), (e, r) => {
|
|
115
|
+
if (e) {
|
|
116
|
+
console.log("Redis hget error:", e);
|
|
117
|
+
reject(e);
|
|
118
|
+
} else {
|
|
119
|
+
resolve(convertRedisHashToJson(r));
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
deleteHashKey(hash, key) {
|
|
126
|
+
return new Promise((resolve, reject) => {
|
|
127
|
+
this.redisClient.hdel(properKey(key, hash), key, (err) => {
|
|
128
|
+
if (err) {
|
|
129
|
+
logger.error("Redis hdel error:", err);
|
|
130
|
+
reject(err);
|
|
131
|
+
} else {
|
|
132
|
+
resolve();
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
get(key) {
|
|
139
|
+
return this.redisClient.getAsync(properKey(key));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
getAsync(key) {
|
|
143
|
+
return promisify(this.redisClient.get(key)).bind(this.redisClient)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
/* a single key write with optional expiry */
|
|
148
|
+
// returns bluebird promise
|
|
149
|
+
writeKey(key, value, expiry) {
|
|
150
|
+
key = this.servicePrefix + key;
|
|
151
|
+
if (expiry) {
|
|
152
|
+
return this.redisClient.setAsync(key, value, "EX", expiry);
|
|
153
|
+
} else {
|
|
154
|
+
return this.redisClient.setAsync(key, value);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
deleteKey(key) {
|
|
159
|
+
return redisClient.delAsync(properKey(key));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
expire(path, expiry) {
|
|
163
|
+
return this.redisClient.expire(path, expiry);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
exists(path) {
|
|
167
|
+
return this.redisClient.exists(path);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
deleteAllKeys() {
|
|
171
|
+
return new Promise((resolve, reject) => {
|
|
172
|
+
if(process.env.NODE_ENV === "production") {
|
|
173
|
+
throw new Error("Clearing system cache is not permitted in production");
|
|
174
|
+
}
|
|
175
|
+
this.redisClient.flushdb((err, res) => {
|
|
176
|
+
if (err) {
|
|
177
|
+
reject(err);
|
|
178
|
+
} else {
|
|
179
|
+
resolve(res);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export default function(config, servicePrefix) {
|
|
187
|
+
return new Cache(config, servicePrefix)
|
|
188
|
+
}
|
package/health/index.js
CHANGED
|
@@ -35,7 +35,8 @@ class HealthCheck {
|
|
|
35
35
|
this.healthChecks = [];
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
/*
|
|
38
|
+
/* Deprecated and replaced by setupCheck
|
|
39
|
+
* call this with an async function, must support wait capability
|
|
39
40
|
*
|
|
40
41
|
* const dbCheck = async () => {
|
|
41
42
|
* return { name: "db", "result": "success", critical: false };
|
|
@@ -62,12 +63,15 @@ class HealthCheck {
|
|
|
62
63
|
return router
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
// v2 version of health check
|
|
66
|
+
// v2 version of health check, replaced addCheck
|
|
67
|
+
// example:
|
|
68
|
+
// const checkRedisFcn = async () => { await cache.ping().then(() => true) }
|
|
69
|
+
// setupCheck({ name: "redis", checkResult: false, critical: false, healthFunction: checkRedisFcn });
|
|
66
70
|
setupCheck(config) {
|
|
67
71
|
this.healthChecks.push(config);
|
|
68
72
|
}
|
|
69
73
|
|
|
70
|
-
/* performs health checks and returns 200 if true and 500 if not */
|
|
74
|
+
/* performs health checks and returns 200 if true and 500 if not */
|
|
71
75
|
async checkHealth(req, res) {
|
|
72
76
|
const checkFormat = pathHelper.extname(req.baseUrl);
|
|
73
77
|
|
|
@@ -82,7 +86,7 @@ class HealthCheck {
|
|
|
82
86
|
} else {
|
|
83
87
|
let res = { name: hc.name, critical: hc.critical }
|
|
84
88
|
try {
|
|
85
|
-
|
|
89
|
+
await hc.healthFunction();
|
|
86
90
|
return { ...res, "result": "success" };
|
|
87
91
|
} catch(e) {
|
|
88
92
|
return { ...res, "result": "fail", status: e.status }
|
|
@@ -148,6 +152,7 @@ class HealthCheck {
|
|
|
148
152
|
res.status(status).send(status_message);
|
|
149
153
|
}
|
|
150
154
|
} catch(error) {
|
|
155
|
+
console.debug("error: ", error)
|
|
151
156
|
res.status(500).send();
|
|
152
157
|
}
|
|
153
158
|
}
|
package/package.json
CHANGED
package/package.tar.gz
CHANGED
|
Binary file
|