@digitalwalletcorp/redis-pooling 1.1.0 → 1.2.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 +9 -3
- package/lib/redis-pooling.d.ts +26 -7
- package/lib/redis-pooling.js +201 -141
- package/lib/redis-pooling.js.map +1 -1
- package/package.json +6 -5
- package/src/redis-pooling.ts +206 -141
package/README.md
CHANGED
|
@@ -101,8 +101,10 @@ async function manageCache() {
|
|
|
101
101
|
console.log('Matching keys:', keys);
|
|
102
102
|
|
|
103
103
|
// Delete all matching keys using UNLINK
|
|
104
|
-
const
|
|
105
|
-
|
|
104
|
+
const delResults = await client.deleteKeys('cache:*');
|
|
105
|
+
const succeeded = delResults.filter(a => a.status === 'fulfilled');
|
|
106
|
+
const delCount = succeeded.reduce((acc, cur) => acc + (cur as PromiseFulfilledResult<number>).value, 0);
|
|
107
|
+
console.log(`Deleted ${delCount} keys`);
|
|
106
108
|
} finally {
|
|
107
109
|
await redisPool.release(client);
|
|
108
110
|
}
|
|
@@ -122,6 +124,7 @@ Creates a Redis connection pool.
|
|
|
122
124
|
| `max` | number | 10 | Maximum number of clients in the pool. |
|
|
123
125
|
| `min` | number | 0 | Minimum number of clients in the pool. |
|
|
124
126
|
| `connectTimeout` | number | 5000 | Connection timeout in milliseconds. |
|
|
127
|
+
| `acquireTimeout` | number | 10000 | Timeout in milliseconds to acquire a client from the pool. |
|
|
125
128
|
| `testOnBorrow` | boolean | true | Enable connection validate on borrow. |
|
|
126
129
|
| `enableTls` | boolean | false | Enable TLS for Redis connection. |
|
|
127
130
|
|
|
@@ -140,13 +143,16 @@ Extends the standard `ioredis` `Redis` client with additional helpers:
|
|
|
140
143
|
| Method | Signature | Description |
|
|
141
144
|
| ----------------------------- | ------------------- | ----------------------------------------------------------------------------------------------- |
|
|
142
145
|
| `getKeys(pattern: string)` | `Promise<string[]>` | Scan and return all keys matching a pattern. |
|
|
143
|
-
| `deleteKeys(pattern: string)` | `Promise<number>` | Scan and delete all keys matching a pattern using `UNLINK`. Returns the number of deleted
|
|
146
|
+
| `deleteKeys(pattern: string)` | `Promise<PromiseSettledResult<number>[]>` | Scan and delete all keys matching a pattern using `UNLINK`. Returns an array of results, one for each batch processed by `UNLINK`. Each result contains the number of keys deleted in that batch. |
|
|
144
147
|
|
|
145
148
|
#### 🗄 Database Index Handling
|
|
146
149
|
|
|
147
150
|
This library provides a Redis connection pool capable of managing Redis clients
|
|
148
151
|
connected to different database indexes (`SELECT db`).
|
|
149
152
|
|
|
153
|
+
All database indexes share a single pool, so `max` is the upper limit of connections to the Redis server.
|
|
154
|
+
The database index is selected every time a client is acquired.
|
|
155
|
+
|
|
150
156
|
**Calling `acquire(dbIndex)`:**
|
|
151
157
|
|
|
152
158
|
> When `dbIndex` is specified, the acquired client will be connected to the specified database index.
|
package/lib/redis-pooling.d.ts
CHANGED
|
@@ -3,29 +3,48 @@ export interface RedisConfig {
|
|
|
3
3
|
url: string;
|
|
4
4
|
dbIndex?: number;
|
|
5
5
|
connectTimeout?: number;
|
|
6
|
+
acquireTimeout?: number;
|
|
6
7
|
max?: number;
|
|
7
8
|
min?: number;
|
|
8
9
|
testOnBorrow?: boolean;
|
|
9
10
|
enableTls?: boolean;
|
|
10
11
|
}
|
|
11
12
|
export interface RedisClient extends Redis {
|
|
12
|
-
getKeys(pattern: string): Promise<string[]>;
|
|
13
|
-
deleteKeys(pattern: string): Promise<number>;
|
|
14
|
-
_originalDbIndex?: number;
|
|
13
|
+
getKeys(pattern: string, count?: number): Promise<string[]>;
|
|
14
|
+
deleteKeys(pattern: string, count?: number): Promise<PromiseSettledResult<number>[]>;
|
|
15
15
|
}
|
|
16
16
|
export declare class RedisPool {
|
|
17
17
|
private readonly url;
|
|
18
18
|
private readonly db;
|
|
19
19
|
private readonly connectTimeout;
|
|
20
|
+
private readonly acquireTimeout;
|
|
20
21
|
private readonly max;
|
|
21
22
|
private readonly min;
|
|
22
23
|
private readonly testOnBorrow;
|
|
23
|
-
private readonly
|
|
24
|
-
private
|
|
25
|
-
|
|
24
|
+
private readonly tls?;
|
|
25
|
+
private pool?;
|
|
26
|
+
private initialized;
|
|
27
|
+
private readonly debug;
|
|
28
|
+
constructor(config: RedisConfig, options?: {
|
|
29
|
+
debug?: boolean;
|
|
30
|
+
});
|
|
26
31
|
acquire(dbIndex?: number): Promise<RedisClient>;
|
|
27
32
|
release(client?: RedisClient): Promise<void>;
|
|
28
33
|
destroy(timeoutMs?: number): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* 初めてacquireが呼ばれた時に、指定された接続情報で接続できるかチェックする
|
|
36
|
+
*
|
|
37
|
+
* @param {number} dbIndex
|
|
38
|
+
*/
|
|
39
|
+
private checkConnectivity;
|
|
40
|
+
/**
|
|
41
|
+
* Redisクライアントの接続が完了するまで待つ。接続に失敗した場合は、そのエラーで reject する
|
|
42
|
+
*
|
|
43
|
+
* @param {Redis} client
|
|
44
|
+
*/
|
|
45
|
+
private waitForReady;
|
|
46
|
+
private ping;
|
|
47
|
+
debugLog(...args: any[]): void;
|
|
29
48
|
private getPool;
|
|
30
|
-
private
|
|
49
|
+
private createPool;
|
|
31
50
|
}
|
package/lib/redis-pooling.js
CHANGED
|
@@ -38,6 +38,7 @@ const ioredis_1 = require("ioredis");
|
|
|
38
38
|
const genericPool = __importStar(require("generic-pool"));
|
|
39
39
|
const logHeader = '[RedisPooling]';
|
|
40
40
|
const DEFAULT_CONNECT_TIMEOUT = 5000;
|
|
41
|
+
const DEFAULT_ACQUIRE_TIMEOUT = 10000;
|
|
41
42
|
const DEFAULT_MAX_POOLING_SIZE = 10;
|
|
42
43
|
const DEFAULT_MIN_POOLING_SIZE = 0;
|
|
43
44
|
const REDIS_PING_TIMEOUT_MS = 3000; // 3秒
|
|
@@ -45,136 +46,203 @@ class RedisPool {
|
|
|
45
46
|
url;
|
|
46
47
|
db;
|
|
47
48
|
connectTimeout;
|
|
49
|
+
acquireTimeout;
|
|
48
50
|
max;
|
|
49
51
|
min;
|
|
50
52
|
testOnBorrow;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
tls;
|
|
54
|
+
pool;
|
|
55
|
+
initialized = false;
|
|
56
|
+
debug;
|
|
57
|
+
constructor(config, options) {
|
|
54
58
|
if (!config.url) {
|
|
55
59
|
throw new Error(`${logHeader} Redis connection url is required.`);
|
|
56
60
|
}
|
|
57
61
|
this.url = config.url;
|
|
58
62
|
this.db = config.dbIndex ?? 0;
|
|
59
63
|
this.connectTimeout = config.connectTimeout ?? DEFAULT_CONNECT_TIMEOUT;
|
|
64
|
+
this.acquireTimeout = config.acquireTimeout ?? DEFAULT_ACQUIRE_TIMEOUT;
|
|
60
65
|
this.max = config.max ?? DEFAULT_MAX_POOLING_SIZE;
|
|
61
66
|
this.min = config.min ?? DEFAULT_MIN_POOLING_SIZE;
|
|
62
67
|
this.testOnBorrow = config.testOnBorrow ?? true;
|
|
63
|
-
this.
|
|
68
|
+
this.tls = config.enableTls ? { rejectUnauthorized: false } : undefined;
|
|
69
|
+
this.debug = options?.debug ?? false;
|
|
64
70
|
}
|
|
65
71
|
async acquire(dbIndex) {
|
|
72
|
+
if (!this.initialized) {
|
|
73
|
+
// 初回acquire呼び出し時のみ接続チェックを行う
|
|
74
|
+
// ホスト不正やパスワード不正による接続不可等を検知する
|
|
75
|
+
// ※ generic-poolのfactoryの方に入ってしまうとエラーを呼び出し元に伝播させることが難しいため、プールとは別の接続でチェックする
|
|
76
|
+
await this.checkConnectivity(dbIndex ?? this.db);
|
|
77
|
+
this.initialized = true;
|
|
78
|
+
}
|
|
66
79
|
const index = dbIndex ?? this.db;
|
|
67
|
-
const pool = this.getPool(
|
|
80
|
+
const pool = this.getPool();
|
|
68
81
|
const client = await pool.acquire();
|
|
69
|
-
|
|
82
|
+
try {
|
|
83
|
+
// プールの接続は、前の利用者が選択したDBを保持したまま返却される。そのため貸し出すたびに対象のDBを選択する
|
|
84
|
+
await client.select(index);
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
await pool.destroy(client);
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
90
|
+
this.debugLog(logHeader, `Redis client ${index} has been acquired.`);
|
|
70
91
|
return client;
|
|
71
92
|
}
|
|
72
93
|
async release(client) {
|
|
73
|
-
if (client) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
needDestroy = true;
|
|
85
|
-
break;
|
|
86
|
-
case client.status === 'ready':
|
|
87
|
-
try {
|
|
88
|
-
// 元のDBインデックスに戻す
|
|
89
|
-
await client.select(dbIndex);
|
|
90
|
-
}
|
|
91
|
-
catch (error) {
|
|
92
|
-
// selectに失敗する→Redisクライアントが不正な状態にあると判断できるのでプールから破棄
|
|
93
|
-
needDestroy = true;
|
|
94
|
-
}
|
|
95
|
-
break;
|
|
96
|
-
default:
|
|
97
|
-
}
|
|
98
|
-
if (needDestroy) {
|
|
99
|
-
// Redisクライアントの破棄
|
|
100
|
-
await pool.destroy(client);
|
|
101
|
-
console.debug(logHeader, `Redis client ${dbIndex} destroyed due to invalid status.`);
|
|
102
|
-
}
|
|
103
|
-
else {
|
|
104
|
-
// Redisクライアントの返却
|
|
105
|
-
await pool.release(client);
|
|
106
|
-
console.debug(logHeader, `Redis client ${dbIndex} released.`);
|
|
107
|
-
}
|
|
94
|
+
if (!client || !this.pool) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (client.status === 'end' || client.status === 'close') {
|
|
98
|
+
// 再利用できない状態のRedisクライアントはプールから破棄する
|
|
99
|
+
await this.pool.destroy(client);
|
|
100
|
+
this.debugLog(logHeader, 'Redis client destroyed due to invalid status.');
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
await this.pool.release(client);
|
|
104
|
+
this.debugLog(logHeader, 'Redis client released.');
|
|
108
105
|
}
|
|
109
106
|
}
|
|
110
107
|
async destroy(timeoutMs = 5000) {
|
|
111
|
-
|
|
112
|
-
|
|
108
|
+
const pool = this.pool;
|
|
109
|
+
if (!pool) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
this.debugLog(logHeader, 'Destroying Redis pool...');
|
|
113
|
+
let timer;
|
|
114
|
+
try {
|
|
113
115
|
await Promise.race([
|
|
114
116
|
(async () => {
|
|
115
117
|
await pool.drain();
|
|
116
118
|
await pool.clear();
|
|
117
119
|
})(),
|
|
118
120
|
new Promise((_, reject) => {
|
|
119
|
-
setTimeout(() => reject(new Error(`${logHeader} Timeout while draining Redis pool
|
|
121
|
+
timer = setTimeout(() => reject(new Error(`${logHeader} Timeout while draining Redis pool`)), timeoutMs);
|
|
120
122
|
})
|
|
121
123
|
]);
|
|
122
|
-
console.debug(logHeader, `Redis pool for DB index ${dbIndex} destroyed.`);
|
|
123
|
-
this.poolMap.delete(dbIndex);
|
|
124
124
|
}
|
|
125
|
+
finally {
|
|
126
|
+
clearTimeout(timer);
|
|
127
|
+
}
|
|
128
|
+
this.debugLog(logHeader, 'Redis pool destroyed.');
|
|
129
|
+
this.pool = undefined;
|
|
125
130
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
+
/**
|
|
132
|
+
* 初めてacquireが呼ばれた時に、指定された接続情報で接続できるかチェックする
|
|
133
|
+
*
|
|
134
|
+
* @param {number} dbIndex
|
|
135
|
+
*/
|
|
136
|
+
async checkConnectivity(dbIndex) {
|
|
137
|
+
const client = new ioredis_1.Redis(this.url, {
|
|
138
|
+
db: dbIndex,
|
|
139
|
+
retryStrategy: () => null, // 再接続無効
|
|
140
|
+
reconnectOnError: () => false, // 再接続無効
|
|
141
|
+
connectTimeout: this.connectTimeout,
|
|
142
|
+
tls: this.tls,
|
|
143
|
+
});
|
|
144
|
+
try {
|
|
145
|
+
await this.waitForReady(client);
|
|
146
|
+
}
|
|
147
|
+
finally {
|
|
148
|
+
client.quit().catch(() => client.disconnect());
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Redisクライアントの接続が完了するまで待つ。接続に失敗した場合は、そのエラーで reject する
|
|
153
|
+
*
|
|
154
|
+
* @param {Redis} client
|
|
155
|
+
*/
|
|
156
|
+
async waitForReady(client) {
|
|
157
|
+
if (client.status === 'ready') {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
return new Promise((resolve, reject) => {
|
|
161
|
+
const onReady = () => {
|
|
162
|
+
cleanup();
|
|
163
|
+
resolve();
|
|
164
|
+
};
|
|
165
|
+
const onError = (error) => {
|
|
166
|
+
cleanup();
|
|
167
|
+
reject(error);
|
|
168
|
+
};
|
|
169
|
+
const cleanup = () => {
|
|
170
|
+
client.off('ready', onReady);
|
|
171
|
+
client.off('error', onError);
|
|
172
|
+
};
|
|
173
|
+
client.once('ready', onReady);
|
|
174
|
+
client.once('error', onError);
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
async ping(client) {
|
|
178
|
+
try {
|
|
179
|
+
this.debugLog(logHeader, 'start validate');
|
|
180
|
+
const timeout = new Promise((_, reject) => {
|
|
181
|
+
setTimeout(() => reject(new Error(`Redis PING timeout after ${REDIS_PING_TIMEOUT_MS}ms`)), REDIS_PING_TIMEOUT_MS);
|
|
182
|
+
});
|
|
183
|
+
await Promise.race([
|
|
184
|
+
client.ping(),
|
|
185
|
+
timeout
|
|
186
|
+
]);
|
|
187
|
+
this.debugLog(logHeader, 'ping succeeded');
|
|
188
|
+
return client.status === 'ready';
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
this.debugLog(logHeader, 'ping failed');
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
debugLog(...args) {
|
|
196
|
+
if (this.debug) {
|
|
197
|
+
console.debug(...args);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
getPool() {
|
|
201
|
+
if (!this.pool) {
|
|
202
|
+
this.pool = this.createPool();
|
|
131
203
|
}
|
|
132
|
-
return pool;
|
|
204
|
+
return this.pool;
|
|
133
205
|
}
|
|
134
|
-
|
|
206
|
+
createPool() {
|
|
135
207
|
const factory = {
|
|
136
208
|
create: async () => {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
if (process.env.NODE_ENV !== 'test') {
|
|
148
|
-
console.debug(logHeader, `retry strategy called ${times} times. delaying ${delay}ms`);
|
|
149
|
-
}
|
|
150
|
-
return delay;
|
|
151
|
-
},
|
|
152
|
-
reconnectOnError: (error) => {
|
|
153
|
-
process.emitWarning(`${logHeader} detected error (on reconnect). ${error.message}`);
|
|
154
|
-
return true;
|
|
209
|
+
const client = new ioredis_1.Redis(this.url, {
|
|
210
|
+
db: this.db,
|
|
211
|
+
connectTimeout: this.connectTimeout,
|
|
212
|
+
keepAlive: 1,
|
|
213
|
+
enableOfflineQueue: true,
|
|
214
|
+
tls: this.tls,
|
|
215
|
+
retryStrategy: (times) => {
|
|
216
|
+
const delay = Math.min(times * 50, 1000);
|
|
217
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
218
|
+
this.debugLog(logHeader, `retry strategy called ${times} times. delaying ${delay}ms`);
|
|
155
219
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
220
|
+
return delay;
|
|
221
|
+
},
|
|
222
|
+
reconnectOnError: (error) => {
|
|
223
|
+
process.emitWarning(`${logHeader} detected error (on reconnectOnError). ${error.message}`);
|
|
224
|
+
// フェイルオーバー後にレプリカへ接続したままになっている場合だけ、再接続で解消できる
|
|
225
|
+
return error.message.startsWith('READONLY');
|
|
226
|
+
}
|
|
227
|
+
});
|
|
163
228
|
client.on('error', error => {
|
|
164
229
|
process.emitWarning(`${logHeader} detected error (on error). ${error.message}`);
|
|
165
230
|
});
|
|
231
|
+
// カスタムメソッド内の処理でthis.debugLogなどが参照できなくなるため、poolのインスタンスを変数キャプチャする
|
|
232
|
+
const poolInstance = this;
|
|
166
233
|
// カスタムメソッド START
|
|
167
234
|
/**
|
|
168
235
|
* 指定されたパターンに一致するキーを Redis から全て取得する
|
|
169
236
|
*
|
|
170
237
|
* @param {string} pattern
|
|
238
|
+
* @param {number} [count] 1度にスキャンする件数 デフォルト:1000
|
|
171
239
|
* @returns {Promise<string[]>}
|
|
172
240
|
*/
|
|
173
|
-
client.getKeys = async function (pattern) {
|
|
241
|
+
client.getKeys = async function (pattern, count) {
|
|
174
242
|
const allKeys = [];
|
|
175
243
|
const stream = this.scanStream({
|
|
176
244
|
match: pattern,
|
|
177
|
-
count:
|
|
245
|
+
count: count ?? 1000
|
|
178
246
|
});
|
|
179
247
|
return new Promise((resolve, reject) => {
|
|
180
248
|
stream.on('data', (keys) => {
|
|
@@ -182,106 +250,98 @@ class RedisPool {
|
|
|
182
250
|
allKeys.push(...keys);
|
|
183
251
|
}
|
|
184
252
|
});
|
|
185
|
-
stream.
|
|
186
|
-
stream.
|
|
187
|
-
console.error(logHeader, `Error during getKeys scan for pattern '${pattern}'.`, err);
|
|
253
|
+
stream.once('end', () => resolve(allKeys));
|
|
254
|
+
stream.once('error', (err) => {
|
|
188
255
|
reject(err);
|
|
189
256
|
});
|
|
190
257
|
});
|
|
191
258
|
};
|
|
192
259
|
/**
|
|
193
260
|
* 指定されたパターンに一致するキーを Redis から全て削除する (UNLINKを使用)
|
|
261
|
+
* 返却値の配列サイズはscanStreamが'data'を受信した回数で、この受信したデータで削除された件数がvalueに設定されている。
|
|
262
|
+
*
|
|
263
|
+
* [
|
|
264
|
+
* { status: 'fulfilled', value: 100 }, // 1バッチ目で100件削除
|
|
265
|
+
* { status: 'fulfilled', value: 80 } // 2バッチ目で80件削除
|
|
266
|
+
* ]
|
|
267
|
+
*
|
|
268
|
+
* 成功した件数は以下のようにして取得可能
|
|
269
|
+
*
|
|
270
|
+
* const delResults = await redisClient.deleteKeys('pattern');
|
|
271
|
+
* const delCount = delResults.filter(a => a.status === 'fulfilled')
|
|
272
|
+
* .reduce((acc, cur) => acc + (cur as PromiseFulfilledResult<number>).value, 0);
|
|
194
273
|
*
|
|
195
274
|
* @param {string} pattern
|
|
196
|
-
* @
|
|
275
|
+
* @param {number} [count] 1度にスキャンする件数 デフォルト:1000
|
|
276
|
+
* @returns {Promise<PromiseSettledResult<number>>}
|
|
197
277
|
*/
|
|
198
|
-
client.deleteKeys = async function (pattern) {
|
|
199
|
-
let deletedCount = 0;
|
|
278
|
+
client.deleteKeys = async function (pattern, count) {
|
|
200
279
|
const stream = this.scanStream({
|
|
201
280
|
match: pattern,
|
|
202
|
-
count:
|
|
281
|
+
count: count ?? 1000
|
|
203
282
|
});
|
|
283
|
+
const results = [];
|
|
204
284
|
return new Promise((resolve, reject) => {
|
|
205
|
-
const tasks = [];
|
|
206
285
|
stream.on('data', async (keys) => {
|
|
207
286
|
if (keys.length) {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
287
|
+
stream.pause();
|
|
288
|
+
try {
|
|
289
|
+
// UNLINK を使用し、現在のインスタンス (this) で実行
|
|
290
|
+
const unlinkResult = await this.unlink(...keys);
|
|
291
|
+
results.push({
|
|
292
|
+
status: 'fulfilled',
|
|
293
|
+
value: unlinkResult
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
catch (err) {
|
|
297
|
+
results.push({
|
|
298
|
+
status: 'rejected',
|
|
299
|
+
reason: err
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
finally {
|
|
303
|
+
stream.resume();
|
|
304
|
+
}
|
|
219
305
|
}
|
|
220
306
|
});
|
|
221
|
-
stream.
|
|
222
|
-
|
|
223
|
-
resolve(deletedCount);
|
|
307
|
+
stream.once('end', async () => {
|
|
308
|
+
resolve(results);
|
|
224
309
|
});
|
|
225
|
-
stream.
|
|
226
|
-
console.error(logHeader, `Error during deleteKeys scan for pattern '${pattern}'.`, err);
|
|
310
|
+
stream.once('error', (err) => {
|
|
227
311
|
reject(err);
|
|
228
312
|
});
|
|
229
313
|
});
|
|
230
314
|
};
|
|
231
315
|
// カスタムメソッド END
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
// cleanup();
|
|
241
|
-
// reject(error);
|
|
242
|
-
// };
|
|
243
|
-
// const cleanup = () => {
|
|
244
|
-
// client.off('ready', onReady);
|
|
245
|
-
// client.off('error', onError);
|
|
246
|
-
// };
|
|
247
|
-
// client.once('ready', onReady);
|
|
248
|
-
// client.once('error', onError);
|
|
249
|
-
// });
|
|
316
|
+
try {
|
|
317
|
+
await this.waitForReady(client);
|
|
318
|
+
}
|
|
319
|
+
catch (error) {
|
|
320
|
+
// 接続できなかったクライアントはプールに入れない。ioredisの再接続も止める
|
|
321
|
+
client.disconnect();
|
|
322
|
+
throw error;
|
|
323
|
+
}
|
|
250
324
|
return client;
|
|
251
325
|
},
|
|
252
326
|
destroy: async (client) => {
|
|
253
327
|
try {
|
|
254
328
|
await client.quit();
|
|
255
|
-
|
|
329
|
+
this.debugLog(logHeader, 'client quit');
|
|
256
330
|
}
|
|
257
331
|
catch (error) {
|
|
258
332
|
client.disconnect();
|
|
259
|
-
|
|
333
|
+
this.debugLog(logHeader, 'client disconnected');
|
|
260
334
|
}
|
|
261
335
|
},
|
|
262
336
|
validate: async (client) => {
|
|
263
|
-
|
|
264
|
-
console.debug(logHeader, 'start validate');
|
|
265
|
-
const timeout = new Promise((_, reject) => {
|
|
266
|
-
setTimeout(() => reject(new Error(`Redis PING timeout after ${REDIS_PING_TIMEOUT_MS}ms`)), REDIS_PING_TIMEOUT_MS);
|
|
267
|
-
});
|
|
268
|
-
await Promise.race([
|
|
269
|
-
client.ping(),
|
|
270
|
-
timeout
|
|
271
|
-
]);
|
|
272
|
-
console.debug(logHeader, 'ping succeeded');
|
|
273
|
-
return client.status === 'ready';
|
|
274
|
-
}
|
|
275
|
-
catch (error) {
|
|
276
|
-
console.debug(logHeader, 'ping failed');
|
|
277
|
-
return false;
|
|
278
|
-
}
|
|
337
|
+
return await this.ping(client);
|
|
279
338
|
}
|
|
280
339
|
};
|
|
281
340
|
return genericPool.createPool(factory, {
|
|
282
341
|
max: this.max,
|
|
283
342
|
min: this.min,
|
|
284
|
-
testOnBorrow: this.testOnBorrow
|
|
343
|
+
testOnBorrow: this.testOnBorrow,
|
|
344
|
+
acquireTimeoutMillis: this.acquireTimeout
|
|
285
345
|
});
|
|
286
346
|
}
|
|
287
347
|
}
|
package/lib/redis-pooling.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redis-pooling.js","sourceRoot":"","sources":["../src/redis-pooling.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qCAAgC;AAChC,0DAA4C;AAkB5C,MAAM,SAAS,GAAG,gBAAgB,CAAC;AACnC,MAAM,uBAAuB,GAAG,IAAI,CAAC;AACrC,MAAM,wBAAwB,GAAG,EAAE,CAAC;AACpC,MAAM,wBAAwB,GAAG,CAAC,CAAC;AACnC,MAAM,qBAAqB,GAAG,IAAI,CAAC,CAAC,KAAK;AAEzC,MAAa,SAAS;IAEH,GAAG,CAAS;IACZ,EAAE,CAAS;IACX,cAAc,CAAS;IACvB,GAAG,CAAS;IACZ,GAAG,CAAS;IACZ,YAAY,CAAU;IACtB,
|
|
1
|
+
{"version":3,"file":"redis-pooling.js","sourceRoot":"","sources":["../src/redis-pooling.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@digitalwalletcorp/redis-pooling",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.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",
|
|
@@ -34,12 +34,13 @@
|
|
|
34
34
|
],
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/ioredis-mock": "^8.2.6",
|
|
37
|
-
"@types/jest": "^
|
|
37
|
+
"@types/jest": "^30.0.0",
|
|
38
38
|
"ioredis-mock": "^8.13.1",
|
|
39
|
-
"jest": "^
|
|
40
|
-
"ts-jest": "^29.
|
|
39
|
+
"jest": "^30.3.0",
|
|
40
|
+
"ts-jest": "^29.4.9",
|
|
41
41
|
"ts-node": "^10.9.2",
|
|
42
|
-
"
|
|
42
|
+
"tsconfig-paths": "^4.2.0",
|
|
43
|
+
"typescript": "^6.0.3"
|
|
43
44
|
},
|
|
44
45
|
"dependencies": {
|
|
45
46
|
"generic-pool": "^3.9.0",
|
package/src/redis-pooling.ts
CHANGED
|
@@ -5,6 +5,7 @@ export interface RedisConfig {
|
|
|
5
5
|
url: string;
|
|
6
6
|
dbIndex?: number;
|
|
7
7
|
connectTimeout?: number;
|
|
8
|
+
acquireTimeout?: number;
|
|
8
9
|
max?: number;
|
|
9
10
|
min?: number;
|
|
10
11
|
testOnBorrow?: boolean;
|
|
@@ -12,13 +13,13 @@ export interface RedisConfig {
|
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
export interface RedisClient extends Redis {
|
|
15
|
-
getKeys(pattern: string): Promise<string[]>;
|
|
16
|
-
deleteKeys(pattern: string): Promise<number>;
|
|
17
|
-
_originalDbIndex?: number; // 内部状態管理用変数
|
|
16
|
+
getKeys(pattern: string, count?: number): Promise<string[]>;
|
|
17
|
+
deleteKeys(pattern: string, count?: number): Promise<PromiseSettledResult<number>[]>;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
const logHeader = '[RedisPooling]';
|
|
21
21
|
const DEFAULT_CONNECT_TIMEOUT = 5000;
|
|
22
|
+
const DEFAULT_ACQUIRE_TIMEOUT = 10000;
|
|
22
23
|
const DEFAULT_MAX_POOLING_SIZE = 10;
|
|
23
24
|
const DEFAULT_MIN_POOLING_SIZE = 0;
|
|
24
25
|
const REDIS_PING_TIMEOUT_MS = 3000; // 3秒
|
|
@@ -28,14 +29,19 @@ export class RedisPool {
|
|
|
28
29
|
private readonly url: string;
|
|
29
30
|
private readonly db: number;
|
|
30
31
|
private readonly connectTimeout: number;
|
|
32
|
+
private readonly acquireTimeout: number;
|
|
31
33
|
private readonly max: number;
|
|
32
34
|
private readonly min: number;
|
|
33
35
|
private readonly testOnBorrow: boolean;
|
|
34
|
-
private readonly
|
|
36
|
+
private readonly tls?: { rejectUnauthorized: false };
|
|
35
37
|
|
|
36
|
-
private
|
|
38
|
+
private pool?: genericPool.Pool<RedisClient>;
|
|
39
|
+
private initialized = false;
|
|
40
|
+
private readonly debug: boolean;
|
|
37
41
|
|
|
38
|
-
constructor(config: RedisConfig
|
|
42
|
+
constructor(config: RedisConfig, options?: {
|
|
43
|
+
debug?: boolean;
|
|
44
|
+
}) {
|
|
39
45
|
if (!config.url) {
|
|
40
46
|
throw new Error(`${logHeader} Redis connection url is required.`);
|
|
41
47
|
}
|
|
@@ -43,130 +49,198 @@ export class RedisPool {
|
|
|
43
49
|
this.url = config.url;
|
|
44
50
|
this.db = config.dbIndex ?? 0;
|
|
45
51
|
this.connectTimeout = config.connectTimeout ?? DEFAULT_CONNECT_TIMEOUT;
|
|
52
|
+
this.acquireTimeout = config.acquireTimeout ?? DEFAULT_ACQUIRE_TIMEOUT;
|
|
46
53
|
this.max = config.max ?? DEFAULT_MAX_POOLING_SIZE;
|
|
47
54
|
this.min = config.min ?? DEFAULT_MIN_POOLING_SIZE;
|
|
48
55
|
this.testOnBorrow = config.testOnBorrow ?? true;
|
|
49
|
-
this.
|
|
56
|
+
this.tls = config.enableTls ? { rejectUnauthorized: false } : undefined;
|
|
57
|
+
|
|
58
|
+
this.debug = options?.debug ?? false;
|
|
50
59
|
}
|
|
51
60
|
|
|
52
61
|
public async acquire(dbIndex?: number): Promise<RedisClient> {
|
|
62
|
+
if (!this.initialized) {
|
|
63
|
+
// 初回acquire呼び出し時のみ接続チェックを行う
|
|
64
|
+
// ホスト不正やパスワード不正による接続不可等を検知する
|
|
65
|
+
// ※ generic-poolのfactoryの方に入ってしまうとエラーを呼び出し元に伝播させることが難しいため、プールとは別の接続でチェックする
|
|
66
|
+
await this.checkConnectivity(dbIndex ?? this.db);
|
|
67
|
+
this.initialized = true;
|
|
68
|
+
}
|
|
69
|
+
|
|
53
70
|
const index = dbIndex ?? this.db;
|
|
54
|
-
const pool = this.getPool(
|
|
71
|
+
const pool = this.getPool();
|
|
55
72
|
const client = await pool.acquire();
|
|
56
|
-
|
|
57
|
-
|
|
73
|
+
try {
|
|
74
|
+
// プールの接続は、前の利用者が選択したDBを保持したまま返却される。そのため貸し出すたびに対象のDBを選択する
|
|
75
|
+
await client.select(index);
|
|
76
|
+
} catch (error) {
|
|
77
|
+
await pool.destroy(client);
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
this.debugLog(logHeader, `Redis client ${index} has been acquired.`);
|
|
58
81
|
return client;
|
|
59
82
|
}
|
|
60
83
|
|
|
61
84
|
public async release(client?: RedisClient): Promise<void> {
|
|
62
|
-
if (client) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
// Redisクライアントの状態が再利用できない場合はプールから破棄
|
|
73
|
-
needDestroy = true;
|
|
74
|
-
break;
|
|
75
|
-
case client.status === 'ready':
|
|
76
|
-
try {
|
|
77
|
-
// 元のDBインデックスに戻す
|
|
78
|
-
await client.select(dbIndex);
|
|
79
|
-
} catch (error) {
|
|
80
|
-
// selectに失敗する→Redisクライアントが不正な状態にあると判断できるのでプールから破棄
|
|
81
|
-
needDestroy = true;
|
|
82
|
-
}
|
|
83
|
-
break;
|
|
84
|
-
default:
|
|
85
|
-
}
|
|
86
|
-
if (needDestroy) {
|
|
87
|
-
// Redisクライアントの破棄
|
|
88
|
-
await pool.destroy(client);
|
|
89
|
-
console.debug(logHeader, `Redis client ${dbIndex} destroyed due to invalid status.`);
|
|
90
|
-
} else {
|
|
91
|
-
// Redisクライアントの返却
|
|
92
|
-
await pool.release(client);
|
|
93
|
-
console.debug(logHeader, `Redis client ${dbIndex} released.`);
|
|
94
|
-
}
|
|
85
|
+
if (!client || !this.pool) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (client.status === 'end' || client.status === 'close') {
|
|
89
|
+
// 再利用できない状態のRedisクライアントはプールから破棄する
|
|
90
|
+
await this.pool.destroy(client);
|
|
91
|
+
this.debugLog(logHeader, 'Redis client destroyed due to invalid status.');
|
|
92
|
+
} else {
|
|
93
|
+
await this.pool.release(client);
|
|
94
|
+
this.debugLog(logHeader, 'Redis client released.');
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
public async destroy(timeoutMs = 5000): Promise<void> {
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
const pool = this.pool;
|
|
100
|
+
if (!pool) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
this.debugLog(logHeader, 'Destroying Redis pool...');
|
|
104
|
+
let timer: NodeJS.Timeout | undefined;
|
|
105
|
+
try {
|
|
101
106
|
await Promise.race([
|
|
102
107
|
(async () => {
|
|
103
108
|
await pool.drain();
|
|
104
109
|
await pool.clear();
|
|
105
110
|
})(),
|
|
106
111
|
new Promise<void>((_, reject) => {
|
|
107
|
-
setTimeout(() => reject(new Error(`${logHeader} Timeout while draining Redis pool
|
|
112
|
+
timer = setTimeout(() => reject(new Error(`${logHeader} Timeout while draining Redis pool`)), timeoutMs);
|
|
108
113
|
})
|
|
109
114
|
]);
|
|
110
|
-
|
|
111
|
-
|
|
115
|
+
} finally {
|
|
116
|
+
clearTimeout(timer);
|
|
112
117
|
}
|
|
118
|
+
this.debugLog(logHeader, 'Redis pool destroyed.');
|
|
119
|
+
this.pool = undefined;
|
|
113
120
|
}
|
|
114
121
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
122
|
+
/**
|
|
123
|
+
* 初めてacquireが呼ばれた時に、指定された接続情報で接続できるかチェックする
|
|
124
|
+
*
|
|
125
|
+
* @param {number} dbIndex
|
|
126
|
+
*/
|
|
127
|
+
private async checkConnectivity(dbIndex: number): Promise<void> {
|
|
128
|
+
const client = new Redis(this.url, {
|
|
129
|
+
db: dbIndex,
|
|
130
|
+
retryStrategy: () => null, // 再接続無効
|
|
131
|
+
reconnectOnError: () => false, // 再接続無効
|
|
132
|
+
connectTimeout: this.connectTimeout,
|
|
133
|
+
tls: this.tls,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
await this.waitForReady(client);
|
|
138
|
+
} finally {
|
|
139
|
+
client.quit().catch(() => client.disconnect());
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Redisクライアントの接続が完了するまで待つ。接続に失敗した場合は、そのエラーで reject する
|
|
145
|
+
*
|
|
146
|
+
* @param {Redis} client
|
|
147
|
+
*/
|
|
148
|
+
private async waitForReady(client: Redis): Promise<void> {
|
|
149
|
+
if (client.status === 'ready') {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
return new Promise<void>((resolve, reject) => {
|
|
153
|
+
const onReady = () => {
|
|
154
|
+
cleanup();
|
|
155
|
+
resolve();
|
|
156
|
+
};
|
|
157
|
+
const onError = (error: Error) => {
|
|
158
|
+
cleanup();
|
|
159
|
+
reject(error);
|
|
160
|
+
};
|
|
161
|
+
const cleanup = () => {
|
|
162
|
+
client.off('ready', onReady);
|
|
163
|
+
client.off('error', onError);
|
|
164
|
+
};
|
|
165
|
+
client.once('ready', onReady);
|
|
166
|
+
client.once('error', onError);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
private async ping(client: Redis): Promise<boolean> {
|
|
171
|
+
try {
|
|
172
|
+
this.debugLog(logHeader, 'start validate');
|
|
173
|
+
const timeout = new Promise<void>((_, reject) => {
|
|
174
|
+
setTimeout(() => reject(new Error(`Redis PING timeout after ${REDIS_PING_TIMEOUT_MS}ms`)), REDIS_PING_TIMEOUT_MS);
|
|
175
|
+
});
|
|
176
|
+
await Promise.race([
|
|
177
|
+
client.ping(),
|
|
178
|
+
timeout
|
|
179
|
+
]);
|
|
180
|
+
this.debugLog(logHeader, 'ping succeeded');
|
|
181
|
+
return client.status === 'ready';
|
|
182
|
+
} catch (error: any) {
|
|
183
|
+
this.debugLog(logHeader, 'ping failed');
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
public debugLog(...args: any[]): void {
|
|
189
|
+
if (this.debug) {
|
|
190
|
+
console.debug(...args);
|
|
120
191
|
}
|
|
121
|
-
return pool;
|
|
122
192
|
}
|
|
123
193
|
|
|
124
|
-
private
|
|
194
|
+
private getPool(): genericPool.Pool<RedisClient> {
|
|
195
|
+
if (!this.pool) {
|
|
196
|
+
this.pool = this.createPool();
|
|
197
|
+
}
|
|
198
|
+
return this.pool;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
private createPool(): genericPool.Pool<RedisClient> {
|
|
125
202
|
const factory: genericPool.Factory<RedisClient> = {
|
|
126
203
|
create: async (): Promise<RedisClient> => {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
if (process.env.NODE_ENV !== 'test') {
|
|
138
|
-
console.debug(logHeader, `retry strategy called ${times} times. delaying ${delay}ms`);
|
|
139
|
-
}
|
|
140
|
-
return delay;
|
|
141
|
-
},
|
|
142
|
-
reconnectOnError: (error) => {
|
|
143
|
-
process.emitWarning(`${logHeader} detected error (on reconnect). ${error.message}`);
|
|
144
|
-
return true;
|
|
204
|
+
const client = new Redis(this.url, {
|
|
205
|
+
db: this.db,
|
|
206
|
+
connectTimeout: this.connectTimeout,
|
|
207
|
+
keepAlive: 1,
|
|
208
|
+
enableOfflineQueue: true,
|
|
209
|
+
tls: this.tls,
|
|
210
|
+
retryStrategy: (times) => {
|
|
211
|
+
const delay = Math.min(times * 50, 1000);
|
|
212
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
213
|
+
this.debugLog(logHeader, `retry strategy called ${times} times. delaying ${delay}ms`);
|
|
145
214
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
215
|
+
return delay;
|
|
216
|
+
},
|
|
217
|
+
reconnectOnError: (error) => {
|
|
218
|
+
process.emitWarning(`${logHeader} detected error (on reconnectOnError). ${error.message}`);
|
|
219
|
+
// フェイルオーバー後にレプリカへ接続したままになっている場合だけ、再接続で解消できる
|
|
220
|
+
return error.message.startsWith('READONLY');
|
|
221
|
+
}
|
|
222
|
+
}) as RedisClient;
|
|
153
223
|
client.on('error', error => {
|
|
154
224
|
process.emitWarning(`${logHeader} detected error (on error). ${error.message}`);
|
|
155
225
|
});
|
|
156
226
|
|
|
227
|
+
// カスタムメソッド内の処理でthis.debugLogなどが参照できなくなるため、poolのインスタンスを変数キャプチャする
|
|
228
|
+
const poolInstance = this;
|
|
229
|
+
|
|
157
230
|
// カスタムメソッド START
|
|
158
231
|
|
|
159
232
|
/**
|
|
160
233
|
* 指定されたパターンに一致するキーを Redis から全て取得する
|
|
161
234
|
*
|
|
162
235
|
* @param {string} pattern
|
|
236
|
+
* @param {number} [count] 1度にスキャンする件数 デフォルト:1000
|
|
163
237
|
* @returns {Promise<string[]>}
|
|
164
238
|
*/
|
|
165
|
-
client.getKeys = async function(pattern: string): Promise<string[]> {
|
|
239
|
+
client.getKeys = async function(pattern: string, count?: number): Promise<string[]> {
|
|
166
240
|
const allKeys: string[] = [];
|
|
167
241
|
const stream = this.scanStream({
|
|
168
242
|
match: pattern,
|
|
169
|
-
count:
|
|
243
|
+
count: count ?? 1000
|
|
170
244
|
});
|
|
171
245
|
|
|
172
246
|
return new Promise((resolve, reject) => {
|
|
@@ -175,107 +249,98 @@ export class RedisPool {
|
|
|
175
249
|
allKeys.push(...keys);
|
|
176
250
|
}
|
|
177
251
|
});
|
|
178
|
-
stream.
|
|
179
|
-
stream.
|
|
180
|
-
console.error(logHeader, `Error during getKeys scan for pattern '${pattern}'.`, err);
|
|
252
|
+
stream.once('end', () => resolve(allKeys));
|
|
253
|
+
stream.once('error', (err: Error) => {
|
|
181
254
|
reject(err);
|
|
182
255
|
});
|
|
183
256
|
});
|
|
184
257
|
};
|
|
185
258
|
/**
|
|
186
259
|
* 指定されたパターンに一致するキーを Redis から全て削除する (UNLINKを使用)
|
|
260
|
+
* 返却値の配列サイズはscanStreamが'data'を受信した回数で、この受信したデータで削除された件数がvalueに設定されている。
|
|
261
|
+
*
|
|
262
|
+
* [
|
|
263
|
+
* { status: 'fulfilled', value: 100 }, // 1バッチ目で100件削除
|
|
264
|
+
* { status: 'fulfilled', value: 80 } // 2バッチ目で80件削除
|
|
265
|
+
* ]
|
|
266
|
+
*
|
|
267
|
+
* 成功した件数は以下のようにして取得可能
|
|
268
|
+
*
|
|
269
|
+
* const delResults = await redisClient.deleteKeys('pattern');
|
|
270
|
+
* const delCount = delResults.filter(a => a.status === 'fulfilled')
|
|
271
|
+
* .reduce((acc, cur) => acc + (cur as PromiseFulfilledResult<number>).value, 0);
|
|
187
272
|
*
|
|
188
273
|
* @param {string} pattern
|
|
189
|
-
* @
|
|
274
|
+
* @param {number} [count] 1度にスキャンする件数 デフォルト:1000
|
|
275
|
+
* @returns {Promise<PromiseSettledResult<number>>}
|
|
190
276
|
*/
|
|
191
|
-
client.deleteKeys = async function(pattern: string): Promise<number> {
|
|
192
|
-
let deletedCount = 0;
|
|
277
|
+
client.deleteKeys = async function(pattern: string, count?: number): Promise<PromiseSettledResult<number>[]> {
|
|
193
278
|
const stream = this.scanStream({
|
|
194
279
|
match: pattern,
|
|
195
|
-
count:
|
|
280
|
+
count: count ?? 1000
|
|
196
281
|
});
|
|
282
|
+
const results: PromiseSettledResult<number>[] = [];
|
|
197
283
|
|
|
198
284
|
return new Promise((resolve, reject) => {
|
|
199
|
-
const tasks: Promise<void>[] = [];
|
|
200
285
|
stream.on('data', async (keys: string[]) => {
|
|
201
286
|
if (keys.length) {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
287
|
+
stream.pause();
|
|
288
|
+
try {
|
|
289
|
+
// UNLINK を使用し、現在のインスタンス (this) で実行
|
|
290
|
+
const unlinkResult = await this.unlink(...keys);
|
|
291
|
+
results.push({
|
|
292
|
+
status: 'fulfilled',
|
|
293
|
+
value: unlinkResult
|
|
294
|
+
});
|
|
295
|
+
} catch (err) {
|
|
296
|
+
results.push({
|
|
297
|
+
status: 'rejected',
|
|
298
|
+
reason: err
|
|
299
|
+
});
|
|
300
|
+
} finally {
|
|
301
|
+
stream.resume();
|
|
302
|
+
}
|
|
212
303
|
}
|
|
213
304
|
});
|
|
214
|
-
stream.
|
|
215
|
-
|
|
216
|
-
resolve(deletedCount);
|
|
305
|
+
stream.once('end', async () => {
|
|
306
|
+
resolve(results);
|
|
217
307
|
});
|
|
218
|
-
stream.
|
|
219
|
-
console.error(logHeader, `Error during deleteKeys scan for pattern '${pattern}'.`, err);
|
|
308
|
+
stream.once('error', (err: Error) => {
|
|
220
309
|
reject(err);
|
|
221
310
|
});
|
|
222
311
|
});
|
|
223
312
|
};
|
|
224
313
|
// カスタムメソッド END
|
|
225
314
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
// const onError = (error: Error) => {
|
|
234
|
-
// cleanup();
|
|
235
|
-
// reject(error);
|
|
236
|
-
// };
|
|
237
|
-
// const cleanup = () => {
|
|
238
|
-
// client.off('ready', onReady);
|
|
239
|
-
// client.off('error', onError);
|
|
240
|
-
// };
|
|
241
|
-
// client.once('ready', onReady);
|
|
242
|
-
// client.once('error', onError);
|
|
243
|
-
// });
|
|
315
|
+
try {
|
|
316
|
+
await this.waitForReady(client);
|
|
317
|
+
} catch (error) {
|
|
318
|
+
// 接続できなかったクライアントはプールに入れない。ioredisの再接続も止める
|
|
319
|
+
client.disconnect();
|
|
320
|
+
throw error;
|
|
321
|
+
}
|
|
244
322
|
|
|
245
323
|
return client;
|
|
246
324
|
},
|
|
247
325
|
destroy: async (client: Redis) => {
|
|
248
326
|
try {
|
|
249
327
|
await client.quit();
|
|
250
|
-
|
|
328
|
+
this.debugLog(logHeader, 'client quit');
|
|
251
329
|
} catch (error) {
|
|
252
330
|
client.disconnect();
|
|
253
|
-
|
|
331
|
+
this.debugLog(logHeader, 'client disconnected');
|
|
254
332
|
}
|
|
255
333
|
},
|
|
256
334
|
validate: async (client: Redis) => {
|
|
257
|
-
|
|
258
|
-
console.debug(logHeader, 'start validate');
|
|
259
|
-
const timeout = new Promise<void>((_, reject) => {
|
|
260
|
-
setTimeout(() => reject(new Error(`Redis PING timeout after ${REDIS_PING_TIMEOUT_MS}ms`)), REDIS_PING_TIMEOUT_MS);
|
|
261
|
-
});
|
|
262
|
-
await Promise.race([
|
|
263
|
-
client.ping(),
|
|
264
|
-
timeout
|
|
265
|
-
]);
|
|
266
|
-
console.debug(logHeader, 'ping succeeded');
|
|
267
|
-
return client.status === 'ready';
|
|
268
|
-
} catch (error) {
|
|
269
|
-
console.debug(logHeader, 'ping failed');
|
|
270
|
-
return false;
|
|
271
|
-
}
|
|
335
|
+
return await this.ping(client);
|
|
272
336
|
}
|
|
273
337
|
};
|
|
274
338
|
|
|
275
339
|
return genericPool.createPool(factory, {
|
|
276
340
|
max: this.max,
|
|
277
341
|
min: this.min,
|
|
278
|
-
testOnBorrow: this.testOnBorrow
|
|
342
|
+
testOnBorrow: this.testOnBorrow,
|
|
343
|
+
acquireTimeoutMillis: this.acquireTimeout
|
|
279
344
|
});
|
|
280
345
|
}
|
|
281
346
|
}
|