@digitalwalletcorp/redis-pooling 1.2.0 → 1.4.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/README.md +32 -1
- package/lib/redis-pooling.d.ts +22 -5
- package/lib/redis-pooling.js +53 -22
- package/lib/redis-pooling.js.map +1 -1
- package/package.json +8 -5
- package/src/redis-pooling.ts +71 -26
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ Designed for both server-side Node.js applications and cron-style background job
|
|
|
12
12
|
* **Custom Utilities**: Built-in helper methods like `getKeys(pattern)` and `deleteKeys(pattern)` for convenient Redis key operations.
|
|
13
13
|
* **Connection Validation**: PING-based validation with timeout before borrowing from the pool.
|
|
14
14
|
* **TLS Support**: Optional TLS configuration for secure Redis connections.
|
|
15
|
+
* **Pluggable Logging**: Pass your own logger (`debug` / `info` / `warn` / `error`) to route logs into your application's logging. Without one, `debug` / `info` logs go to the console when `debug` is enabled and warnings go through `process.emitWarning`.
|
|
15
16
|
|
|
16
17
|
#### 📦 Installation
|
|
17
18
|
|
|
@@ -113,7 +114,7 @@ async function manageCache() {
|
|
|
113
114
|
|
|
114
115
|
#### 📚 API Reference
|
|
115
116
|
|
|
116
|
-
##### `new RedisPool(config: RedisConfig)`
|
|
117
|
+
##### `new RedisPool(config: RedisConfig, options?: RedisPoolOptions)`
|
|
117
118
|
|
|
118
119
|
Creates a Redis connection pool.
|
|
119
120
|
|
|
@@ -128,6 +129,35 @@ Creates a Redis connection pool.
|
|
|
128
129
|
| `testOnBorrow` | boolean | true | Enable connection validate on borrow. |
|
|
129
130
|
| `enableTls` | boolean | false | Enable TLS for Redis connection. |
|
|
130
131
|
|
|
132
|
+
`RedisPoolOptions`:
|
|
133
|
+
|
|
134
|
+
| Property | Type | Default | Description |
|
|
135
|
+
| ----------------- | -------------------- | --------- | ------------------------------------------------------------------------------------------------------------- |
|
|
136
|
+
| `logger` | `RedisPoolLogger` | - | Destination of all logs. When given, the logger decides which levels are output (`debug` is ignored). |
|
|
137
|
+
| `debug` | boolean | false | Only used without `logger`. When `true`, `debug` / `info` logs are written to `console.debug` / `console.info`. |
|
|
138
|
+
| `acquireLogLevel` | `'debug' \| 'info'` | `'debug'` | Level used for client acquire / release logs. |
|
|
139
|
+
|
|
140
|
+
`RedisPoolLogger`:
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
interface RedisPoolLogger {
|
|
144
|
+
debug(...args: any[]): void;
|
|
145
|
+
info(...args: any[]): void;
|
|
146
|
+
warn(...args: any[]): void;
|
|
147
|
+
error(...args: any[]): void;
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Each log is called with the header `'[RedisPooling]'`, a message, and optional details, e.g. `logger.error('[RedisPooling]', 'detected error (on error)', error)`.
|
|
152
|
+
|
|
153
|
+
| Level | Messages |
|
|
154
|
+
| ---------------- | --------------------------------------------------------------------------------------------------------------- |
|
|
155
|
+
| `debug` / `info` | `Redis client N has been acquired.`, `Redis client released.`, `Redis client destroyed due to invalid status.` (chosen by `acquireLogLevel`) |
|
|
156
|
+
| `info` | `Destroying Redis pool...`, `Redis pool destroyed.` |
|
|
157
|
+
| `debug` | `start validate`, `ping succeeded`, `retry strategy called ...`, `client quit`, `client disconnected` |
|
|
158
|
+
| `warn` | `ping failed`, `detected error (on reconnectOnError)` |
|
|
159
|
+
| `error` | `detected error (on error)` |
|
|
160
|
+
|
|
131
161
|
##### `RedisPool` Methods
|
|
132
162
|
|
|
133
163
|
| Method | Signature | Description |
|
|
@@ -176,6 +206,7 @@ const client2 = await pool.acquire();
|
|
|
176
206
|
|
|
177
207
|
* Always release clients back to the pool using `release(client)` to avoid connection leaks.
|
|
178
208
|
* Use `acquire()` and `release()` inside `try/finally` blocks for safe resource management.
|
|
209
|
+
* Without `logger`, `warn` / `error` logs are emitted via `process.emitWarning` so that callers can suppress them with the `--no-warnings` flag (e.g. `node --no-warnings app.js`, or `NODE_OPTIONS=--no-warnings`) or handle them with `process.on('warning')`.
|
|
179
210
|
|
|
180
211
|
#### 📜 License
|
|
181
212
|
|
package/lib/redis-pooling.d.ts
CHANGED
|
@@ -9,6 +9,24 @@ export interface RedisConfig {
|
|
|
9
9
|
testOnBorrow?: boolean;
|
|
10
10
|
enableTls?: boolean;
|
|
11
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* ログの出力先
|
|
14
|
+
* 渡した場合、どのレベルを出力するかはこのロガーが決める
|
|
15
|
+
*/
|
|
16
|
+
export interface RedisPoolLogger {
|
|
17
|
+
debug(...args: any[]): void;
|
|
18
|
+
info(...args: any[]): void;
|
|
19
|
+
warn(...args: any[]): void;
|
|
20
|
+
error(...args: any[]): void;
|
|
21
|
+
}
|
|
22
|
+
export interface RedisPoolOptions {
|
|
23
|
+
/** ログの出力先。未指定の場合はconsole(debug/info)とprocess.emitWarning(warn/error)に出力する */
|
|
24
|
+
logger?: RedisPoolLogger;
|
|
25
|
+
/** loggerを渡さない場合のみ有効。trueの場合はdebug/infoも出力する */
|
|
26
|
+
debug?: boolean;
|
|
27
|
+
/** クライアントの貸出・返却ログを出力するレベル */
|
|
28
|
+
acquireLogLevel?: 'debug' | 'info';
|
|
29
|
+
}
|
|
12
30
|
export interface RedisClient extends Redis {
|
|
13
31
|
getKeys(pattern: string, count?: number): Promise<string[]>;
|
|
14
32
|
deleteKeys(pattern: string, count?: number): Promise<PromiseSettledResult<number>[]>;
|
|
@@ -24,10 +42,9 @@ export declare class RedisPool {
|
|
|
24
42
|
private readonly tls?;
|
|
25
43
|
private pool?;
|
|
26
44
|
private initialized;
|
|
27
|
-
private readonly
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
});
|
|
45
|
+
private readonly logger;
|
|
46
|
+
private readonly acquireLogLevel;
|
|
47
|
+
constructor(config: RedisConfig, options?: RedisPoolOptions);
|
|
31
48
|
acquire(dbIndex?: number): Promise<RedisClient>;
|
|
32
49
|
release(client?: RedisClient): Promise<void>;
|
|
33
50
|
destroy(timeoutMs?: number): Promise<void>;
|
|
@@ -44,7 +61,7 @@ export declare class RedisPool {
|
|
|
44
61
|
*/
|
|
45
62
|
private waitForReady;
|
|
46
63
|
private ping;
|
|
47
|
-
|
|
64
|
+
private acquireLog;
|
|
48
65
|
private getPool;
|
|
49
66
|
private createPool;
|
|
50
67
|
}
|
package/lib/redis-pooling.js
CHANGED
|
@@ -32,8 +32,12 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
32
32
|
return result;
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
35
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
39
|
exports.RedisPool = void 0;
|
|
40
|
+
const util_1 = __importDefault(require("util"));
|
|
37
41
|
const ioredis_1 = require("ioredis");
|
|
38
42
|
const genericPool = __importStar(require("generic-pool"));
|
|
39
43
|
const logHeader = '[RedisPooling]';
|
|
@@ -42,6 +46,29 @@ const DEFAULT_ACQUIRE_TIMEOUT = 10000;
|
|
|
42
46
|
const DEFAULT_MAX_POOLING_SIZE = 10;
|
|
43
47
|
const DEFAULT_MIN_POOLING_SIZE = 0;
|
|
44
48
|
const REDIS_PING_TIMEOUT_MS = 3000; // 3秒
|
|
49
|
+
/**
|
|
50
|
+
* loggerが渡されなかった場合のロガー
|
|
51
|
+
* 警告とエラーは呼び出し元が--no-warningsやprocess.on('warning')で抑止・捕捉できるようにprocess.emitWarningで出力する
|
|
52
|
+
*
|
|
53
|
+
* @param {boolean} debug trueの場合はdebug/infoもconsoleに出力する
|
|
54
|
+
* @returns {RedisPoolLogger}
|
|
55
|
+
*/
|
|
56
|
+
function createDefaultLogger(debug) {
|
|
57
|
+
return {
|
|
58
|
+
debug: (...args) => {
|
|
59
|
+
if (debug) {
|
|
60
|
+
console.debug(...args);
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
info: (...args) => {
|
|
64
|
+
if (debug) {
|
|
65
|
+
console.info(...args);
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
warn: (...args) => process.emitWarning(util_1.default.format(...args)),
|
|
69
|
+
error: (...args) => process.emitWarning(util_1.default.format(...args))
|
|
70
|
+
};
|
|
71
|
+
}
|
|
45
72
|
class RedisPool {
|
|
46
73
|
url;
|
|
47
74
|
db;
|
|
@@ -53,7 +80,8 @@ class RedisPool {
|
|
|
53
80
|
tls;
|
|
54
81
|
pool;
|
|
55
82
|
initialized = false;
|
|
56
|
-
|
|
83
|
+
logger;
|
|
84
|
+
acquireLogLevel;
|
|
57
85
|
constructor(config, options) {
|
|
58
86
|
if (!config.url) {
|
|
59
87
|
throw new Error(`${logHeader} Redis connection url is required.`);
|
|
@@ -66,7 +94,8 @@ class RedisPool {
|
|
|
66
94
|
this.min = config.min ?? DEFAULT_MIN_POOLING_SIZE;
|
|
67
95
|
this.testOnBorrow = config.testOnBorrow ?? true;
|
|
68
96
|
this.tls = config.enableTls ? { rejectUnauthorized: false } : undefined;
|
|
69
|
-
this.
|
|
97
|
+
this.logger = options?.logger ?? createDefaultLogger(options?.debug ?? false);
|
|
98
|
+
this.acquireLogLevel = options?.acquireLogLevel ?? 'debug';
|
|
70
99
|
}
|
|
71
100
|
async acquire(dbIndex) {
|
|
72
101
|
if (!this.initialized) {
|
|
@@ -87,7 +116,7 @@ class RedisPool {
|
|
|
87
116
|
await pool.destroy(client);
|
|
88
117
|
throw error;
|
|
89
118
|
}
|
|
90
|
-
this.
|
|
119
|
+
this.acquireLog(logHeader, `Redis client ${index} has been acquired.`);
|
|
91
120
|
return client;
|
|
92
121
|
}
|
|
93
122
|
async release(client) {
|
|
@@ -97,11 +126,11 @@ class RedisPool {
|
|
|
97
126
|
if (client.status === 'end' || client.status === 'close') {
|
|
98
127
|
// 再利用できない状態のRedisクライアントはプールから破棄する
|
|
99
128
|
await this.pool.destroy(client);
|
|
100
|
-
this.
|
|
129
|
+
this.acquireLog(logHeader, 'Redis client destroyed due to invalid status.');
|
|
101
130
|
}
|
|
102
131
|
else {
|
|
103
132
|
await this.pool.release(client);
|
|
104
|
-
this.
|
|
133
|
+
this.acquireLog(logHeader, 'Redis client released.');
|
|
105
134
|
}
|
|
106
135
|
}
|
|
107
136
|
async destroy(timeoutMs = 5000) {
|
|
@@ -109,7 +138,7 @@ class RedisPool {
|
|
|
109
138
|
if (!pool) {
|
|
110
139
|
return;
|
|
111
140
|
}
|
|
112
|
-
this.
|
|
141
|
+
this.logger.info(logHeader, 'Destroying Redis pool...');
|
|
113
142
|
let timer;
|
|
114
143
|
try {
|
|
115
144
|
await Promise.race([
|
|
@@ -125,7 +154,7 @@ class RedisPool {
|
|
|
125
154
|
finally {
|
|
126
155
|
clearTimeout(timer);
|
|
127
156
|
}
|
|
128
|
-
this.
|
|
157
|
+
this.logger.info(logHeader, 'Redis pool destroyed.');
|
|
129
158
|
this.pool = undefined;
|
|
130
159
|
}
|
|
131
160
|
/**
|
|
@@ -175,28 +204,32 @@ class RedisPool {
|
|
|
175
204
|
});
|
|
176
205
|
}
|
|
177
206
|
async ping(client) {
|
|
207
|
+
let timer;
|
|
178
208
|
try {
|
|
179
|
-
this.
|
|
209
|
+
this.logger.debug(logHeader, 'start validate');
|
|
180
210
|
const timeout = new Promise((_, reject) => {
|
|
181
|
-
setTimeout(() => reject(new Error(`Redis PING timeout after ${REDIS_PING_TIMEOUT_MS}ms`)), REDIS_PING_TIMEOUT_MS);
|
|
211
|
+
timer = setTimeout(() => reject(new Error(`Redis PING timeout after ${REDIS_PING_TIMEOUT_MS}ms`)), REDIS_PING_TIMEOUT_MS);
|
|
182
212
|
});
|
|
183
213
|
await Promise.race([
|
|
184
214
|
client.ping(),
|
|
185
215
|
timeout
|
|
186
216
|
]);
|
|
187
|
-
this.
|
|
217
|
+
this.logger.debug(logHeader, 'ping succeeded');
|
|
188
218
|
return client.status === 'ready';
|
|
189
219
|
}
|
|
190
220
|
catch (error) {
|
|
191
|
-
|
|
221
|
+
// 検証に失敗した接続はプールから破棄される
|
|
222
|
+
this.logger.warn(logHeader, 'ping failed', error);
|
|
192
223
|
return false;
|
|
193
224
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
console.debug(...args);
|
|
225
|
+
finally {
|
|
226
|
+
// PINGが先に応答した場合もタイマーを残さない
|
|
227
|
+
clearTimeout(timer);
|
|
198
228
|
}
|
|
199
229
|
}
|
|
230
|
+
acquireLog(...args) {
|
|
231
|
+
this.logger[this.acquireLogLevel](...args);
|
|
232
|
+
}
|
|
200
233
|
getPool() {
|
|
201
234
|
if (!this.pool) {
|
|
202
235
|
this.pool = this.createPool();
|
|
@@ -215,21 +248,19 @@ class RedisPool {
|
|
|
215
248
|
retryStrategy: (times) => {
|
|
216
249
|
const delay = Math.min(times * 50, 1000);
|
|
217
250
|
if (process.env.NODE_ENV !== 'test') {
|
|
218
|
-
this.
|
|
251
|
+
this.logger.debug(logHeader, `retry strategy called ${times} times. delaying ${delay}ms`);
|
|
219
252
|
}
|
|
220
253
|
return delay;
|
|
221
254
|
},
|
|
222
255
|
reconnectOnError: (error) => {
|
|
223
|
-
|
|
256
|
+
this.logger.warn(logHeader, 'detected error (on reconnectOnError)', error);
|
|
224
257
|
// フェイルオーバー後にレプリカへ接続したままになっている場合だけ、再接続で解消できる
|
|
225
258
|
return error.message.startsWith('READONLY');
|
|
226
259
|
}
|
|
227
260
|
});
|
|
228
261
|
client.on('error', error => {
|
|
229
|
-
|
|
262
|
+
this.logger.error(logHeader, 'detected error (on error)', error);
|
|
230
263
|
});
|
|
231
|
-
// カスタムメソッド内の処理でthis.debugLogなどが参照できなくなるため、poolのインスタンスを変数キャプチャする
|
|
232
|
-
const poolInstance = this;
|
|
233
264
|
// カスタムメソッド START
|
|
234
265
|
/**
|
|
235
266
|
* 指定されたパターンに一致するキーを Redis から全て取得する
|
|
@@ -326,11 +357,11 @@ class RedisPool {
|
|
|
326
357
|
destroy: async (client) => {
|
|
327
358
|
try {
|
|
328
359
|
await client.quit();
|
|
329
|
-
this.
|
|
360
|
+
this.logger.debug(logHeader, 'client quit');
|
|
330
361
|
}
|
|
331
362
|
catch (error) {
|
|
332
363
|
client.disconnect();
|
|
333
|
-
this.
|
|
364
|
+
this.logger.debug(logHeader, 'client disconnected');
|
|
334
365
|
}
|
|
335
366
|
},
|
|
336
367
|
validate: async (client) => {
|
package/lib/redis-pooling.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redis-pooling.js","sourceRoot":"","sources":["../src/redis-pooling.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"redis-pooling.js","sourceRoot":"","sources":["../src/redis-pooling.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,gDAAwB;AACxB,qCAAgC;AAChC,0DAA4C;AAsC5C,MAAM,SAAS,GAAG,gBAAgB,CAAC;AACnC,MAAM,uBAAuB,GAAG,IAAI,CAAC;AACrC,MAAM,uBAAuB,GAAG,KAAK,CAAC;AACtC,MAAM,wBAAwB,GAAG,EAAE,CAAC;AACpC,MAAM,wBAAwB,GAAG,CAAC,CAAC;AACnC,MAAM,qBAAqB,GAAG,IAAI,CAAC,CAAC,KAAK;AAEzC;;;;;;GAMG;AACH,SAAS,mBAAmB,CAAC,KAAc;IACzC,OAAO;QACL,KAAK,EAAE,CAAC,GAAG,IAAW,EAAE,EAAE;YACxB,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;QACD,IAAI,EAAE,CAAC,GAAG,IAAW,EAAE,EAAE;YACvB,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;QACD,IAAI,EAAE,CAAC,GAAG,IAAW,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,cAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;QACnE,KAAK,EAAE,CAAC,GAAG,IAAW,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,cAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;KACrE,CAAC;AACJ,CAAC;AAED,MAAa,SAAS;IAEH,GAAG,CAAS;IACZ,EAAE,CAAS;IACX,cAAc,CAAS;IACvB,cAAc,CAAS;IACvB,GAAG,CAAS;IACZ,GAAG,CAAS;IACZ,YAAY,CAAU;IACtB,GAAG,CAAiC;IAE7C,IAAI,CAAiC;IACrC,WAAW,GAAG,KAAK,CAAC;IACX,MAAM,CAAkB;IACxB,eAAe,CAAmB;IAEnD,YAAY,MAAmB,EAAE,OAA0B;QACzD,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,GAAG,SAAS,oCAAoC,CAAC,CAAC;QACpE,CAAC;QAED,IAAI,CAAC,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC;QACtB,IAAI,CAAC,EAAE,GAAG,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC;QAC9B,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,IAAI,uBAAuB,CAAC;QACvE,IAAI,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,IAAI,uBAAuB,CAAC;QACvE,IAAI,CAAC,GAAG,GAAG,MAAM,CAAC,GAAG,IAAI,wBAAwB,CAAC;QAClD,IAAI,CAAC,GAAG,GAAG,MAAM,CAAC,GAAG,IAAI,wBAAwB,CAAC;QAClD,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC,YAAY,IAAI,IAAI,CAAC;QAChD,IAAI,CAAC,GAAG,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAExE,IAAI,CAAC,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,mBAAmB,CAAC,OAAO,EAAE,KAAK,IAAI,KAAK,CAAC,CAAC;QAC9E,IAAI,CAAC,eAAe,GAAG,OAAO,EAAE,eAAe,IAAI,OAAO,CAAC;IAC7D,CAAC;IAEM,KAAK,CAAC,OAAO,CAAC,OAAgB;QACnC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,4BAA4B;YAC5B,6BAA6B;YAC7B,2EAA2E;YAC3E,MAAM,IAAI,CAAC,iBAAiB,CAAC,OAAO,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC;YACjD,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QAC1B,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,IAAI,IAAI,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACpC,IAAI,CAAC;YACH,yDAAyD;YACzD,MAAM,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAC3B,MAAM,KAAK,CAAC;QACd,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,gBAAgB,KAAK,qBAAqB,CAAC,CAAC;QACvE,OAAO,MAAM,CAAC;IAChB,CAAC;IAEM,KAAK,CAAC,OAAO,CAAC,MAAoB;QACvC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YAC1B,OAAO;QACT,CAAC;QACD,IAAI,MAAM,CAAC,MAAM,KAAK,KAAK,IAAI,MAAM,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;YACzD,kCAAkC;YAClC,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAChC,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,+CAA+C,CAAC,CAAC;QAC9E,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAChC,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,wBAAwB,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,OAAO,CAAC,SAAS,GAAG,IAAI;QACnC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACvB,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO;QACT,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,0BAA0B,CAAC,CAAC;QACxD,IAAI,KAAiC,CAAC;QACtC,IAAI,CAAC;YACH,MAAM,OAAO,CAAC,IAAI,CAAC;gBACjB,CAAC,KAAK,IAAI,EAAE;oBACV,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;oBACnB,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;gBACrB,CAAC,CAAC,EAAE;gBACJ,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE;oBAC9B,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,SAAS,oCAAoC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;gBAC3G,CAAC,CAAC;aACH,CAAC,CAAC;QACL,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,uBAAuB,CAAC,CAAC;QACrD,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC;IACxB,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,iBAAiB,CAAC,OAAe;QAC7C,MAAM,MAAM,GAAG,IAAI,eAAK,CAAC,IAAI,CAAC,GAAG,EAAE;YACjC,EAAE,EAAE,OAAO;YACX,aAAa,EAAE,GAAG,EAAE,CAAC,IAAI,EAAM,QAAQ;YACvC,gBAAgB,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,QAAQ;YACvC,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,GAAG,EAAE,IAAI,CAAC,GAAG;SACd,CAAC,CAAC;QAEH,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QAClC,CAAC;gBAAS,CAAC;YACT,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,YAAY,CAAC,MAAa;QACtC,IAAI,MAAM,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;YAC9B,OAAO;QACT,CAAC;QACD,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC3C,MAAM,OAAO,GAAG,GAAG,EAAE;gBACnB,OAAO,EAAE,CAAC;gBACV,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC;YACF,MAAM,OAAO,GAAG,CAAC,KAAY,EAAE,EAAE;gBAC/B,OAAO,EAAE,CAAC;gBACV,MAAM,CAAC,KAAK,CAAC,CAAC;YAChB,CAAC,CAAC;YACF,MAAM,OAAO,GAAG,GAAG,EAAE;gBACnB,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;gBAC7B,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC/B,CAAC,CAAC;YACF,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC9B,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAChC,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,IAAI,CAAC,MAAa;QAC9B,IAAI,KAAiC,CAAC;QACtC,IAAI,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;YAC/C,MAAM,OAAO,GAAG,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE;gBAC9C,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,4BAA4B,qBAAqB,IAAI,CAAC,CAAC,EAAE,qBAAqB,CAAC,CAAC;YAC5H,CAAC,CAAC,CAAC;YACH,MAAM,OAAO,CAAC,IAAI,CAAC;gBACjB,MAAM,CAAC,IAAI,EAAE;gBACb,OAAO;aACR,CAAC,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;YAC/C,OAAO,MAAM,CAAC,MAAM,KAAK,OAAO,CAAC;QACnC,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,uBAAuB;YACvB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,EAAE,KAAK,CAAC,CAAC;YAClD,OAAO,KAAK,CAAC;QACf,CAAC;gBAAS,CAAC;YACT,0BAA0B;YAC1B,YAAY,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAEO,UAAU,CAAC,GAAG,IAAW;QAC/B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAC7C,CAAC;IAEO,OAAO;QACb,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAChC,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAEO,UAAU;QAChB,MAAM,OAAO,GAAqC;YAChD,MAAM,EAAE,KAAK,IAA0B,EAAE;gBACvC,MAAM,MAAM,GAAG,IAAI,eAAK,CAAC,IAAI,CAAC,GAAG,EAAE;oBACjC,EAAE,EAAE,IAAI,CAAC,EAAE;oBACX,cAAc,EAAE,IAAI,CAAC,cAAc;oBACnC,SAAS,EAAE,CAAC;oBACZ,kBAAkB,EAAE,IAAI;oBACxB,GAAG,EAAE,IAAI,CAAC,GAAG;oBACb,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE;wBACvB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC;wBACzC,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;4BACpC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,yBAAyB,KAAK,oBAAoB,KAAK,IAAI,CAAC,CAAC;wBAC5F,CAAC;wBACD,OAAO,KAAK,CAAC;oBACf,CAAC;oBACD,gBAAgB,EAAE,CAAC,KAAK,EAAE,EAAE;wBAC1B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,sCAAsC,EAAE,KAAK,CAAC,CAAC;wBAC3E,4CAA4C;wBAC5C,OAAO,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;oBAC9C,CAAC;iBACF,CAAgB,CAAC;gBAClB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE;oBACzB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,2BAA2B,EAAE,KAAK,CAAC,CAAC;gBACnE,CAAC,CAAC,CAAC;gBAEH,iBAAiB;gBAEjB;;;;;;mBAMG;gBACH,MAAM,CAAC,OAAO,GAAG,KAAK,WAAU,OAAe,EAAE,KAAc;oBAC7D,MAAM,OAAO,GAAa,EAAE,CAAC;oBAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC;wBAC7B,KAAK,EAAE,OAAO;wBACd,KAAK,EAAE,KAAK,IAAI,IAAI;qBACrB,CAAC,CAAC;oBAEH,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;wBACrC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAc,EAAE,EAAE;4BACnC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gCAChB,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;4BACxB,CAAC;wBACH,CAAC,CAAC,CAAC;wBACH,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;wBAC3C,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,GAAU,EAAE,EAAE;4BAClC,MAAM,CAAC,GAAG,CAAC,CAAC;wBACd,CAAC,CAAC,CAAC;oBACL,CAAC,CAAC,CAAC;gBACL,CAAC,CAAC;gBACF;;;;;;;;;;;;;;;;;;mBAkBG;gBACH,MAAM,CAAC,UAAU,GAAG,KAAK,WAAU,OAAe,EAAE,KAAc;oBAChE,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC;wBAC7B,KAAK,EAAE,OAAO;wBACd,KAAK,EAAE,KAAK,IAAI,IAAI;qBACrB,CAAC,CAAC;oBACH,MAAM,OAAO,GAAmC,EAAE,CAAC;oBAEnD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;wBACrC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,IAAc,EAAE,EAAE;4BACzC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gCAChB,MAAM,CAAC,KAAK,EAAE,CAAC;gCACf,IAAI,CAAC;oCACH,mCAAmC;oCACnC,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;oCAChD,OAAO,CAAC,IAAI,CAAC;wCACX,MAAM,EAAE,WAAW;wCACnB,KAAK,EAAE,YAAY;qCACpB,CAAC,CAAC;gCACL,CAAC;gCAAC,OAAO,GAAG,EAAE,CAAC;oCACb,OAAO,CAAC,IAAI,CAAC;wCACX,MAAM,EAAE,UAAU;wCAClB,MAAM,EAAE,GAAG;qCACZ,CAAC,CAAC;gCACL,CAAC;wCAAS,CAAC;oCACT,MAAM,CAAC,MAAM,EAAE,CAAC;gCAClB,CAAC;4BACH,CAAC;wBACH,CAAC,CAAC,CAAC;wBACH,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,IAAI,EAAE;4BAC5B,OAAO,CAAC,OAAO,CAAC,CAAC;wBACnB,CAAC,CAAC,CAAC;wBACH,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,GAAU,EAAE,EAAE;4BAClC,MAAM,CAAC,GAAG,CAAC,CAAC;wBACd,CAAC,CAAC,CAAC;oBACL,CAAC,CAAC,CAAC;gBACL,CAAC,CAAC;gBACF,eAAe;gBAEf,IAAI,CAAC;oBACH,MAAM,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;gBAClC,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,0CAA0C;oBAC1C,MAAM,CAAC,UAAU,EAAE,CAAC;oBACpB,MAAM,KAAK,CAAC;gBACd,CAAC;gBAED,OAAO,MAAM,CAAC;YAChB,CAAC;YACD,OAAO,EAAE,KAAK,EAAE,MAAa,EAAE,EAAE;gBAC/B,IAAI,CAAC;oBACH,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;oBACpB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;gBAC9C,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,MAAM,CAAC,UAAU,EAAE,CAAC;oBACpB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,qBAAqB,CAAC,CAAC;gBACtD,CAAC;YACH,CAAC;YACD,QAAQ,EAAE,KAAK,EAAE,MAAa,EAAE,EAAE;gBAChC,OAAO,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACjC,CAAC;SACF,CAAC;QAEF,OAAO,WAAW,CAAC,UAAU,CAAC,OAAO,EAAE;YACrC,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,oBAAoB,EAAE,IAAI,CAAC,cAAc;SAC1C,CAAC,CAAC;IACL,CAAC;CACF;AA/TD,8BA+TC"}
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@digitalwalletcorp/redis-pooling",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "This is a library for redis connection pooling",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"build": "tsc --project tsconfig.build.json",
|
|
9
|
+
"install:dev": "rm -rf lib dest && find node_modules -mindepth 1 -delete && yarn install",
|
|
9
10
|
"version:patch": "npm version patch",
|
|
10
11
|
"version:minor": "npm version minor",
|
|
11
12
|
"version:major": "npm version major",
|
|
@@ -32,18 +33,20 @@
|
|
|
32
33
|
"lib/**/*",
|
|
33
34
|
"src/**/*"
|
|
34
35
|
],
|
|
36
|
+
"peerDependencies": {
|
|
37
|
+
"generic-pool": ">=3.9.0",
|
|
38
|
+
"ioredis": ">=5.0.0"
|
|
39
|
+
},
|
|
35
40
|
"devDependencies": {
|
|
36
41
|
"@types/ioredis-mock": "^8.2.6",
|
|
37
42
|
"@types/jest": "^30.0.0",
|
|
43
|
+
"generic-pool": "^3.9.0",
|
|
44
|
+
"ioredis": "^5.9.2",
|
|
38
45
|
"ioredis-mock": "^8.13.1",
|
|
39
46
|
"jest": "^30.3.0",
|
|
40
47
|
"ts-jest": "^29.4.9",
|
|
41
48
|
"ts-node": "^10.9.2",
|
|
42
49
|
"tsconfig-paths": "^4.2.0",
|
|
43
50
|
"typescript": "^6.0.3"
|
|
44
|
-
},
|
|
45
|
-
"dependencies": {
|
|
46
|
-
"generic-pool": "^3.9.0",
|
|
47
|
-
"ioredis": "^5.9.2"
|
|
48
51
|
}
|
|
49
52
|
}
|
package/src/redis-pooling.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import util from 'util';
|
|
1
2
|
import { Redis } from 'ioredis';
|
|
2
3
|
import * as genericPool from 'generic-pool';
|
|
3
4
|
|
|
@@ -12,6 +13,26 @@ export interface RedisConfig {
|
|
|
12
13
|
enableTls?: boolean;
|
|
13
14
|
}
|
|
14
15
|
|
|
16
|
+
/**
|
|
17
|
+
* ログの出力先
|
|
18
|
+
* 渡した場合、どのレベルを出力するかはこのロガーが決める
|
|
19
|
+
*/
|
|
20
|
+
export interface RedisPoolLogger {
|
|
21
|
+
debug(...args: any[]): void;
|
|
22
|
+
info(...args: any[]): void;
|
|
23
|
+
warn(...args: any[]): void;
|
|
24
|
+
error(...args: any[]): void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface RedisPoolOptions {
|
|
28
|
+
/** ログの出力先。未指定の場合はconsole(debug/info)とprocess.emitWarning(warn/error)に出力する */
|
|
29
|
+
logger?: RedisPoolLogger;
|
|
30
|
+
/** loggerを渡さない場合のみ有効。trueの場合はdebug/infoも出力する */
|
|
31
|
+
debug?: boolean;
|
|
32
|
+
/** クライアントの貸出・返却ログを出力するレベル */
|
|
33
|
+
acquireLogLevel?: 'debug' | 'info';
|
|
34
|
+
}
|
|
35
|
+
|
|
15
36
|
export interface RedisClient extends Redis {
|
|
16
37
|
getKeys(pattern: string, count?: number): Promise<string[]>;
|
|
17
38
|
deleteKeys(pattern: string, count?: number): Promise<PromiseSettledResult<number>[]>;
|
|
@@ -24,6 +45,30 @@ const DEFAULT_MAX_POOLING_SIZE = 10;
|
|
|
24
45
|
const DEFAULT_MIN_POOLING_SIZE = 0;
|
|
25
46
|
const REDIS_PING_TIMEOUT_MS = 3000; // 3秒
|
|
26
47
|
|
|
48
|
+
/**
|
|
49
|
+
* loggerが渡されなかった場合のロガー
|
|
50
|
+
* 警告とエラーは呼び出し元が--no-warningsやprocess.on('warning')で抑止・捕捉できるようにprocess.emitWarningで出力する
|
|
51
|
+
*
|
|
52
|
+
* @param {boolean} debug trueの場合はdebug/infoもconsoleに出力する
|
|
53
|
+
* @returns {RedisPoolLogger}
|
|
54
|
+
*/
|
|
55
|
+
function createDefaultLogger(debug: boolean): RedisPoolLogger {
|
|
56
|
+
return {
|
|
57
|
+
debug: (...args: any[]) => {
|
|
58
|
+
if (debug) {
|
|
59
|
+
console.debug(...args);
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
info: (...args: any[]) => {
|
|
63
|
+
if (debug) {
|
|
64
|
+
console.info(...args);
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
warn: (...args: any[]) => process.emitWarning(util.format(...args)),
|
|
68
|
+
error: (...args: any[]) => process.emitWarning(util.format(...args))
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
27
72
|
export class RedisPool {
|
|
28
73
|
|
|
29
74
|
private readonly url: string;
|
|
@@ -37,11 +82,10 @@ export class RedisPool {
|
|
|
37
82
|
|
|
38
83
|
private pool?: genericPool.Pool<RedisClient>;
|
|
39
84
|
private initialized = false;
|
|
40
|
-
private readonly
|
|
85
|
+
private readonly logger: RedisPoolLogger;
|
|
86
|
+
private readonly acquireLogLevel: 'debug' | 'info';
|
|
41
87
|
|
|
42
|
-
constructor(config: RedisConfig, options?: {
|
|
43
|
-
debug?: boolean;
|
|
44
|
-
}) {
|
|
88
|
+
constructor(config: RedisConfig, options?: RedisPoolOptions) {
|
|
45
89
|
if (!config.url) {
|
|
46
90
|
throw new Error(`${logHeader} Redis connection url is required.`);
|
|
47
91
|
}
|
|
@@ -55,7 +99,8 @@ export class RedisPool {
|
|
|
55
99
|
this.testOnBorrow = config.testOnBorrow ?? true;
|
|
56
100
|
this.tls = config.enableTls ? { rejectUnauthorized: false } : undefined;
|
|
57
101
|
|
|
58
|
-
this.
|
|
102
|
+
this.logger = options?.logger ?? createDefaultLogger(options?.debug ?? false);
|
|
103
|
+
this.acquireLogLevel = options?.acquireLogLevel ?? 'debug';
|
|
59
104
|
}
|
|
60
105
|
|
|
61
106
|
public async acquire(dbIndex?: number): Promise<RedisClient> {
|
|
@@ -77,7 +122,7 @@ export class RedisPool {
|
|
|
77
122
|
await pool.destroy(client);
|
|
78
123
|
throw error;
|
|
79
124
|
}
|
|
80
|
-
this.
|
|
125
|
+
this.acquireLog(logHeader, `Redis client ${index} has been acquired.`);
|
|
81
126
|
return client;
|
|
82
127
|
}
|
|
83
128
|
|
|
@@ -88,10 +133,10 @@ export class RedisPool {
|
|
|
88
133
|
if (client.status === 'end' || client.status === 'close') {
|
|
89
134
|
// 再利用できない状態のRedisクライアントはプールから破棄する
|
|
90
135
|
await this.pool.destroy(client);
|
|
91
|
-
this.
|
|
136
|
+
this.acquireLog(logHeader, 'Redis client destroyed due to invalid status.');
|
|
92
137
|
} else {
|
|
93
138
|
await this.pool.release(client);
|
|
94
|
-
this.
|
|
139
|
+
this.acquireLog(logHeader, 'Redis client released.');
|
|
95
140
|
}
|
|
96
141
|
}
|
|
97
142
|
|
|
@@ -100,7 +145,7 @@ export class RedisPool {
|
|
|
100
145
|
if (!pool) {
|
|
101
146
|
return;
|
|
102
147
|
}
|
|
103
|
-
this.
|
|
148
|
+
this.logger.info(logHeader, 'Destroying Redis pool...');
|
|
104
149
|
let timer: NodeJS.Timeout | undefined;
|
|
105
150
|
try {
|
|
106
151
|
await Promise.race([
|
|
@@ -115,7 +160,7 @@ export class RedisPool {
|
|
|
115
160
|
} finally {
|
|
116
161
|
clearTimeout(timer);
|
|
117
162
|
}
|
|
118
|
-
this.
|
|
163
|
+
this.logger.info(logHeader, 'Redis pool destroyed.');
|
|
119
164
|
this.pool = undefined;
|
|
120
165
|
}
|
|
121
166
|
|
|
@@ -168,27 +213,30 @@ export class RedisPool {
|
|
|
168
213
|
}
|
|
169
214
|
|
|
170
215
|
private async ping(client: Redis): Promise<boolean> {
|
|
216
|
+
let timer: NodeJS.Timeout | undefined;
|
|
171
217
|
try {
|
|
172
|
-
this.
|
|
218
|
+
this.logger.debug(logHeader, 'start validate');
|
|
173
219
|
const timeout = new Promise<void>((_, reject) => {
|
|
174
|
-
setTimeout(() => reject(new Error(`Redis PING timeout after ${REDIS_PING_TIMEOUT_MS}ms`)), REDIS_PING_TIMEOUT_MS);
|
|
220
|
+
timer = setTimeout(() => reject(new Error(`Redis PING timeout after ${REDIS_PING_TIMEOUT_MS}ms`)), REDIS_PING_TIMEOUT_MS);
|
|
175
221
|
});
|
|
176
222
|
await Promise.race([
|
|
177
223
|
client.ping(),
|
|
178
224
|
timeout
|
|
179
225
|
]);
|
|
180
|
-
this.
|
|
226
|
+
this.logger.debug(logHeader, 'ping succeeded');
|
|
181
227
|
return client.status === 'ready';
|
|
182
228
|
} catch (error: any) {
|
|
183
|
-
|
|
229
|
+
// 検証に失敗した接続はプールから破棄される
|
|
230
|
+
this.logger.warn(logHeader, 'ping failed', error);
|
|
184
231
|
return false;
|
|
232
|
+
} finally {
|
|
233
|
+
// PINGが先に応答した場合もタイマーを残さない
|
|
234
|
+
clearTimeout(timer);
|
|
185
235
|
}
|
|
186
236
|
}
|
|
187
237
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
console.debug(...args);
|
|
191
|
-
}
|
|
238
|
+
private acquireLog(...args: any[]): void {
|
|
239
|
+
this.logger[this.acquireLogLevel](...args);
|
|
192
240
|
}
|
|
193
241
|
|
|
194
242
|
private getPool(): genericPool.Pool<RedisClient> {
|
|
@@ -210,23 +258,20 @@ export class RedisPool {
|
|
|
210
258
|
retryStrategy: (times) => {
|
|
211
259
|
const delay = Math.min(times * 50, 1000);
|
|
212
260
|
if (process.env.NODE_ENV !== 'test') {
|
|
213
|
-
this.
|
|
261
|
+
this.logger.debug(logHeader, `retry strategy called ${times} times. delaying ${delay}ms`);
|
|
214
262
|
}
|
|
215
263
|
return delay;
|
|
216
264
|
},
|
|
217
265
|
reconnectOnError: (error) => {
|
|
218
|
-
|
|
266
|
+
this.logger.warn(logHeader, 'detected error (on reconnectOnError)', error);
|
|
219
267
|
// フェイルオーバー後にレプリカへ接続したままになっている場合だけ、再接続で解消できる
|
|
220
268
|
return error.message.startsWith('READONLY');
|
|
221
269
|
}
|
|
222
270
|
}) as RedisClient;
|
|
223
271
|
client.on('error', error => {
|
|
224
|
-
|
|
272
|
+
this.logger.error(logHeader, 'detected error (on error)', error);
|
|
225
273
|
});
|
|
226
274
|
|
|
227
|
-
// カスタムメソッド内の処理でthis.debugLogなどが参照できなくなるため、poolのインスタンスを変数キャプチャする
|
|
228
|
-
const poolInstance = this;
|
|
229
|
-
|
|
230
275
|
// カスタムメソッド START
|
|
231
276
|
|
|
232
277
|
/**
|
|
@@ -325,10 +370,10 @@ export class RedisPool {
|
|
|
325
370
|
destroy: async (client: Redis) => {
|
|
326
371
|
try {
|
|
327
372
|
await client.quit();
|
|
328
|
-
this.
|
|
373
|
+
this.logger.debug(logHeader, 'client quit');
|
|
329
374
|
} catch (error) {
|
|
330
375
|
client.disconnect();
|
|
331
|
-
this.
|
|
376
|
+
this.logger.debug(logHeader, 'client disconnected');
|
|
332
377
|
}
|
|
333
378
|
},
|
|
334
379
|
validate: async (client: Redis) => {
|