@taicode/common-server 1.0.11 → 1.0.13

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.
Files changed (51) hide show
  1. package/output/index.d.ts +1 -0
  2. package/output/index.d.ts.map +1 -1
  3. package/output/index.js +1 -0
  4. package/output/redis-queue/index.d.ts +6 -4
  5. package/output/redis-queue/index.d.ts.map +1 -1
  6. package/output/redis-queue/index.js +4 -2
  7. package/output/redis-queue/redis-batch-consumer.d.ts +80 -0
  8. package/output/redis-queue/redis-batch-consumer.d.ts.map +1 -0
  9. package/output/redis-queue/redis-batch-consumer.js +308 -0
  10. package/output/redis-queue/redis-batch-consumer.test.d.ts +7 -0
  11. package/output/redis-queue/redis-batch-consumer.test.d.ts.map +1 -0
  12. package/output/redis-queue/redis-batch-consumer.test.js +265 -0
  13. package/output/redis-queue/redis-queue-common.d.ts +73 -0
  14. package/output/redis-queue/redis-queue-common.d.ts.map +1 -0
  15. package/output/redis-queue/redis-queue-common.js +302 -0
  16. package/output/redis-queue/redis-queue-common.test.d.ts +19 -0
  17. package/output/redis-queue/redis-queue-common.test.d.ts.map +1 -0
  18. package/output/redis-queue/redis-queue-common.test.js +623 -0
  19. package/output/redis-queue/redis-queue-consumer.d.ts +81 -0
  20. package/output/redis-queue/redis-queue-consumer.d.ts.map +1 -0
  21. package/output/redis-queue/redis-queue-consumer.js +297 -0
  22. package/output/redis-queue/redis-queue-consumer.test.d.ts +7 -0
  23. package/output/redis-queue/redis-queue-consumer.test.d.ts.map +1 -0
  24. package/output/redis-queue/redis-queue-consumer.test.js +242 -0
  25. package/output/redis-queue/redis-queue-provider.d.ts +56 -0
  26. package/output/redis-queue/redis-queue-provider.d.ts.map +1 -0
  27. package/output/redis-queue/redis-queue-provider.js +187 -0
  28. package/output/redis-queue/redis-queue-provider.test.d.ts +7 -0
  29. package/output/redis-queue/redis-queue-provider.test.d.ts.map +1 -0
  30. package/output/redis-queue/redis-queue-provider.test.js +114 -0
  31. package/output/redis-queue/types.d.ts +77 -19
  32. package/output/redis-queue/types.d.ts.map +1 -1
  33. package/package.json +1 -1
  34. package/output/logger/logger.d.ts +0 -33
  35. package/output/logger/logger.d.ts.map +0 -1
  36. package/output/logger/logger.js +0 -65
  37. package/output/logger/logger.test.d.ts +0 -2
  38. package/output/logger/logger.test.d.ts.map +0 -1
  39. package/output/logger/logger.test.js +0 -87
  40. package/output/redis-queue/batch-redis-queue.d.ts +0 -136
  41. package/output/redis-queue/batch-redis-queue.d.ts.map +0 -1
  42. package/output/redis-queue/batch-redis-queue.js +0 -573
  43. package/output/redis-queue/batch-redis-queue.test.d.ts +0 -2
  44. package/output/redis-queue/batch-redis-queue.test.d.ts.map +0 -1
  45. package/output/redis-queue/batch-redis-queue.test.js +0 -243
  46. package/output/redis-queue/redis-queue.d.ts +0 -129
  47. package/output/redis-queue/redis-queue.d.ts.map +0 -1
  48. package/output/redis-queue/redis-queue.js +0 -547
  49. package/output/redis-queue/redis-queue.test.d.ts +0 -2
  50. package/output/redis-queue/redis-queue.test.d.ts.map +0 -1
  51. package/output/redis-queue/redis-queue.test.js +0 -234
@@ -1,573 +0,0 @@
1
- import { randomUUID } from 'node:crypto';
2
- import { createClient } from 'redis';
3
- import { catchIt } from '@taicode/common-base';
4
- /**
5
- * 批量任务队列类(泛型)
6
- *
7
- * 提供基于 Redis 的批量任务队列功能,支持:
8
- * - 批量处理任务(每次处理多条)
9
- * - 任务入队和持久化
10
- * - 自动重试机制
11
- * - 任务状态追踪
12
- * - 分布式消费
13
- *
14
- * @template T 任务数据类型
15
- *
16
- * @example
17
- * ```ts
18
- * interface EmailTask {
19
- * to: string
20
- * }
21
- *
22
- * const queue = new BatchRedisQueue<EmailTask>({
23
- * redisUrl: 'redis://localhost:6379',
24
- * queueKey: 'email-batch-queue',
25
- * batchSize: 50,
26
- * handler: async (dataList) => {
27
- * await sendEmailsBatch(dataList.map(d => d.to))
28
- * return catchIt(() => {})
29
- * }
30
- * })
31
- *
32
- * // 连接 Redis(自动启动消费者)
33
- * await queue.connect()
34
- *
35
- * // 入队任务(自动开始处理)
36
- * await queue.enqueue([
37
- * { to: 'user1@example.com' },
38
- * { to: 'user2@example.com' },
39
- * ])
40
- *
41
- * // 获取队列统计信息(O(1) 时间复杂度)
42
- * const stats = await queue.statistics()
43
- * console.log(stats) // { pending: 100, processing: 50, completed: 200, failed: 5 }
44
- * ```
45
- */
46
- export class BatchRedisQueue {
47
- consumerRunning = false;
48
- redis = null;
49
- consumerInterval = null;
50
- recoveryInterval = null;
51
- processingBatches = 0; // 当前正在处理的批次数
52
- config;
53
- handler;
54
- // 不同状态队列的键名
55
- failedQueue;
56
- pendingQueue;
57
- processingQueue;
58
- completedQueue;
59
- constructor(config) {
60
- // 验证必填参数
61
- if (!config.redisUrl) {
62
- throw new Error('[BatchTaskQueue] redisUrl is required');
63
- }
64
- if (!config.queueKey) {
65
- throw new Error('[BatchTaskQueue] queueKey is required');
66
- }
67
- if (config.queueKey.length < 6) {
68
- throw new Error('[BatchTaskQueue] queueKey must be at least 6 characters long');
69
- }
70
- if (!config.handler) {
71
- throw new Error('[BatchTaskQueue] handler is required');
72
- }
73
- this.handler = config.handler;
74
- this.config = {
75
- queueKey: config.queueKey,
76
- redisUrl: config.redisUrl,
77
- batchSize: config.batchSize || 10,
78
- maxRetries: config.maxRetries || 3,
79
- concurrency: config.concurrency || 1,
80
- cleanupDelay: config.cleanupDelay || 86400, // 24 hours
81
- processingDelay: config.processingDelay || 0, // 默认立即执行
82
- consumerInterval: config.consumerInterval || 1000,
83
- processingTimeout: config.processingTimeout || 60000, // 60 seconds
84
- };
85
- // 初始化不同状态队列的键名
86
- this.failedQueue = `${config.queueKey}:failed`;
87
- this.pendingQueue = `${config.queueKey}:pending`;
88
- this.completedQueue = `${config.queueKey}:completed`;
89
- this.processingQueue = `${config.queueKey}:processing`;
90
- this.redis = createClient({ url: this.config.redisUrl });
91
- // 添加错误处理
92
- this.redis.on('error', (err) => {
93
- console.error('[BatchTaskQueue] Redis Client Error:', err);
94
- });
95
- }
96
- /**
97
- * 连接 Redis 并自动启动消费者
98
- */
99
- async connect() {
100
- if (this.redis && !this.redis.isOpen) {
101
- await this.redis.connect().catch((error) => {
102
- console.error('[BatchTaskQueue] Failed to connect to Redis:', error);
103
- throw error;
104
- });
105
- // 连接成功后启动消费者和恢复机制
106
- this.startConsumer();
107
- this.startRecovery();
108
- }
109
- }
110
- /**
111
- * 断开 Redis 连接并停止消费者
112
- */
113
- disconnect() {
114
- this.stopConsumer();
115
- this.stopRecovery();
116
- if (this.redis && this.redis.isOpen) {
117
- this.redis.disconnect().catch((error) => {
118
- console.error('[BatchTaskQueue] Failed to disconnect:', error);
119
- });
120
- }
121
- }
122
- async enqueue(data) {
123
- if (!this.redis) {
124
- console.warn('[BatchTaskQueue] Redis not available, skipping task enqueue');
125
- return Array.isArray(data) ? [] : '';
126
- }
127
- // 统一处理为数组
128
- const dataList = Array.isArray(data) ? data : [data];
129
- const taskIds = [];
130
- // 使用 Lua 脚本确保幂等入队的原子性
131
- const enqueueScript = `
132
- local taskKey = KEYS[1]
133
- local pendingQueue = KEYS[2]
134
- local taskData = ARGV[1]
135
- local ttl = tonumber(ARGV[2])
136
- local taskId = ARGV[3]
137
-
138
- -- 检查任务是否已存在
139
- local exists = redis.call('EXISTS', taskKey)
140
- if exists == 1 then
141
- return 0 -- 任务已存在,跳过
142
- end
143
-
144
- -- 原子化操作: 创建任务 + 推入队列
145
- redis.call('SETEX', taskKey, ttl, taskData)
146
- redis.call('RPUSH', pendingQueue, taskId)
147
- return 1 -- 成功创建
148
- `;
149
- for (const item of dataList) {
150
- // 检查 data 中是否包含自定义 id
151
- const customId = item.id;
152
- const taskId = customId || randomUUID();
153
- const taskKey = `${this.config.queueKey}:task:${taskId}`;
154
- const task = {
155
- id: taskId,
156
- data: item,
157
- retryCount: 0,
158
- maxRetries: this.config.maxRetries,
159
- createdTime: new Date().toISOString(),
160
- status: 'pending',
161
- ...(this.config.processingDelay > 0 && { delayUntil: Date.now() + this.config.processingDelay }),
162
- };
163
- // 使用 Lua 脚本原子化入队
164
- const result = await this.redis.eval(enqueueScript, {
165
- keys: [taskKey, this.pendingQueue],
166
- arguments: [JSON.stringify(task), this.config.cleanupDelay.toString(), taskId],
167
- });
168
- if (result === 0) {
169
- console.log(`[BatchTaskQueue] Task already exists, skipping: ${taskId}`);
170
- }
171
- else {
172
- console.log(`[BatchTaskQueue] Enqueued task: ${task.id}`);
173
- }
174
- taskIds.push(taskId);
175
- }
176
- // 返回单个 ID 或 ID 数组
177
- return Array.isArray(data) ? taskIds : taskIds[0];
178
- }
179
- /**
180
- * 获取任务详情
181
- */
182
- async getTask(taskId) {
183
- if (!this.redis)
184
- return null;
185
- const taskKey = `${this.config.queueKey}:task:${taskId}`;
186
- const taskData = await this.redis.get(taskKey);
187
- if (!taskData)
188
- return null;
189
- return JSON.parse(taskData);
190
- }
191
- /**
192
- * 更新任务状态并移动到对应队列(原子操作)
193
- */
194
- async applyStatus(taskId, oldStatus, newStatus) {
195
- if (!this.redis)
196
- return;
197
- const task = await this.getTask(taskId);
198
- if (!task)
199
- return;
200
- task.status = newStatus;
201
- const taskKey = `${this.config.queueKey}:task:${taskId}`;
202
- const oldQueue = this.getQueueByStatus(oldStatus);
203
- const newQueue = this.getQueueByStatus(newStatus);
204
- if (oldQueue !== newQueue) {
205
- // 使用 Lua 脚本确保原子性:更新任务 + 移动队列
206
- const script = `
207
- redis.call('SETEX', KEYS[1], ARGV[1], ARGV[2])
208
- redis.call('LREM', KEYS[2], 0, ARGV[3])
209
- redis.call('RPUSH', KEYS[3], ARGV[3])
210
- return 1
211
- `;
212
- await this.redis.eval(script, {
213
- keys: [taskKey, oldQueue, newQueue],
214
- arguments: [this.config.cleanupDelay.toString(), JSON.stringify(task), taskId],
215
- });
216
- }
217
- else {
218
- // 只更新任务数据
219
- await this.redis.setEx(taskKey, this.config.cleanupDelay, JSON.stringify(task));
220
- }
221
- }
222
- /**
223
- * 批量更新任务状态
224
- */
225
- async applyStatusBatch(taskIds, oldStatus, newStatus) {
226
- await Promise.all(taskIds.map(taskId => this.applyStatus(taskId, oldStatus, newStatus)));
227
- }
228
- /**
229
- * 根据状态获取对应的队列键
230
- */
231
- getQueueByStatus(status) {
232
- switch (status) {
233
- case 'pending': return this.pendingQueue;
234
- case 'processing': return this.processingQueue;
235
- case 'completed': return this.completedQueue;
236
- case 'failed': return this.failedQueue;
237
- default: return this.pendingQueue;
238
- }
239
- }
240
- /**
241
- * 恢复超时的任务
242
- * 检查 processing 队列中的任务,将超时的任务重试或标记为失败
243
- */
244
- async recoverStalledTasks() {
245
- if (!this.redis)
246
- return;
247
- try {
248
- const processingTaskIds = await this.redis.lRange(this.processingQueue, 0, -1);
249
- if (processingTaskIds.length === 0) {
250
- return;
251
- }
252
- const now = Date.now();
253
- let recoveredCount = 0;
254
- for (const taskId of processingTaskIds) {
255
- const task = await this.getTask(taskId);
256
- if (!task) {
257
- // 任务不存在,从队列中移除
258
- await this.redis.lRem(this.processingQueue, 0, taskId);
259
- continue;
260
- }
261
- // 检查是否超时
262
- const processingTime = now - (task.processingStartTime || now);
263
- if (processingTime > this.config.processingTimeout) {
264
- console.log(`[BatchTaskQueue] Task timeout: ${taskId} (processing time: ${processingTime}ms)`);
265
- const taskKey = `${this.config.queueKey}:task:${taskId}`;
266
- // 检查是否还可以重试
267
- if (task.retryCount < task.maxRetries) {
268
- // 重试:放回 pending 队列
269
- task.status = 'pending';
270
- task.retryCount++;
271
- task.processingStartTime = undefined;
272
- // 使用 Lua 脚本确保原子性
273
- const script = `
274
- redis.call('SETEX', KEYS[1], ARGV[1], ARGV[2])
275
- redis.call('LREM', KEYS[2], 0, ARGV[3])
276
- redis.call('RPUSH', KEYS[3], ARGV[3])
277
- return 1
278
- `;
279
- await this.redis.eval(script, {
280
- keys: [taskKey, this.processingQueue, this.pendingQueue],
281
- arguments: [this.config.cleanupDelay.toString(), JSON.stringify(task), taskId],
282
- });
283
- console.log(`[BatchTaskQueue] Task ${taskId} will retry (${task.retryCount}/${task.maxRetries})`);
284
- }
285
- else {
286
- // 已达到最大重试次数,标记为失败
287
- task.status = 'failed';
288
- task.processingStartTime = undefined;
289
- // 使用 Lua 脚本确保原子性
290
- const script = `
291
- redis.call('SETEX', KEYS[1], ARGV[1], ARGV[2])
292
- redis.call('LREM', KEYS[2], 0, ARGV[3])
293
- redis.call('RPUSH', KEYS[3], ARGV[3])
294
- return 1
295
- `;
296
- await this.redis.eval(script, {
297
- keys: [taskKey, this.processingQueue, this.failedQueue],
298
- arguments: [this.config.cleanupDelay.toString(), JSON.stringify(task), taskId],
299
- });
300
- console.error(`[BatchTaskQueue] Task ${taskId} failed after timeout`);
301
- }
302
- recoveredCount++;
303
- }
304
- }
305
- if (recoveredCount > 0) {
306
- console.log(`[BatchTaskQueue] Recovered ${recoveredCount} timeout tasks`);
307
- }
308
- }
309
- catch (error) {
310
- console.error('[BatchTaskQueue] Failed to recover stalled tasks:', error);
311
- }
312
- }
313
- /**
314
- * 批量处理任务
315
- */
316
- async processBatch(taskIds) {
317
- this.processingBatches++;
318
- try {
319
- // 获取所有任务
320
- const tasks = await Promise.all(taskIds.map(id => this.getTask(id)));
321
- const validTasks = tasks.filter((task) => task !== null);
322
- if (validTasks.length === 0) {
323
- console.warn(`[BatchTaskQueue] No valid tasks found in batch`);
324
- return;
325
- }
326
- // 过滤出有效的待处理任务
327
- const tasksToProcess = [];
328
- for (const task of validTasks) {
329
- // 检查状态
330
- if (task.status !== 'pending') {
331
- console.log(`[BatchTaskQueue] Task ${task.id} has invalid status (${task.status}), marking as failed`);
332
- await this.applyStatus(task.id, task.status, 'failed');
333
- continue;
334
- }
335
- tasksToProcess.push(task);
336
- }
337
- if (tasksToProcess.length === 0) {
338
- return;
339
- }
340
- try {
341
- // 任务已在 processing 队列中(由 Lua 脚本完成),只需更新状态和开始时间
342
- const taskIdList = tasksToProcess.map(t => t.id);
343
- const now = Date.now();
344
- await Promise.all(tasksToProcess.map(task => {
345
- task.status = 'processing';
346
- task.processingStartTime = now;
347
- const taskKey = `${this.config.queueKey}:task:${task.id}`;
348
- return this.redis.setEx(taskKey, this.config.cleanupDelay, JSON.stringify(task));
349
- }));
350
- // 执行批量任务处理器
351
- const dataList = tasksToProcess.map(t => t.data);
352
- await this.handler(dataList);
353
- // 更新状态为完成
354
- await this.applyStatusBatch(taskIdList, 'processing', 'completed');
355
- console.log(`[BatchTaskQueue] Batch completed: ${tasksToProcess.length} tasks`);
356
- }
357
- catch (error) {
358
- console.error(`[BatchTaskQueue] Batch failed`, error);
359
- // 检查每个任务是否需要重试
360
- for (const task of tasksToProcess) {
361
- if (task.retryCount < task.maxRetries) {
362
- task.retryCount++;
363
- task.status = 'pending';
364
- task.processingStartTime = undefined;
365
- const taskKey = `${this.config.queueKey}:task:${task.id}`;
366
- // 使用 Lua 脚本确保原子性
367
- const script = `
368
- redis.call('SETEX', KEYS[1], ARGV[1], ARGV[2])
369
- redis.call('LREM', KEYS[2], 0, ARGV[3])
370
- redis.call('RPUSH', KEYS[3], ARGV[3])
371
- return 1
372
- `;
373
- await this.redis.eval(script, {
374
- keys: [taskKey, this.processingQueue, this.pendingQueue],
375
- arguments: [this.config.cleanupDelay.toString(), JSON.stringify(task), task.id],
376
- });
377
- console.log(`[BatchTaskQueue] Task ${task.id} will retry (${task.retryCount}/${task.maxRetries})`);
378
- }
379
- else {
380
- task.status = 'failed';
381
- task.processingStartTime = undefined;
382
- const taskKey = `${this.config.queueKey}:task:${task.id}`;
383
- // 使用 Lua 脚本确保原子性
384
- const script = `
385
- redis.call('SETEX', KEYS[1], ARGV[1], ARGV[2])
386
- redis.call('LREM', KEYS[2], 0, ARGV[3])
387
- redis.call('RPUSH', KEYS[3], ARGV[3])
388
- return 1
389
- `;
390
- await this.redis.eval(script, {
391
- keys: [taskKey, this.processingQueue, this.failedQueue],
392
- arguments: [this.config.cleanupDelay.toString(), JSON.stringify(task), task.id],
393
- });
394
- console.error(`[BatchTaskQueue] Task ${task.id} failed after ${task.maxRetries} retries`);
395
- }
396
- }
397
- }
398
- }
399
- finally {
400
- this.processingBatches--;
401
- }
402
- }
403
- /**
404
- * 启动恢复机制(内部方法,自动调用)
405
- */
406
- startRecovery() {
407
- if (this.recoveryInterval || !this.redis) {
408
- return;
409
- }
410
- // 立即执行一次恢复
411
- this.recoverStalledTasks().catch(error => {
412
- console.error('[BatchTaskQueue] Initial recovery error:', error);
413
- });
414
- // 定期检查(每 10 秒检查一次)
415
- this.recoveryInterval = setInterval(() => {
416
- this.recoverStalledTasks().catch(error => {
417
- console.error('[BatchTaskQueue] Recovery error:', error);
418
- });
419
- }, 10000);
420
- console.log('[BatchTaskQueue] Recovery mechanism started');
421
- }
422
- /**
423
- * 停止恢复机制(内部方法,自动调用)
424
- */
425
- stopRecovery() {
426
- if (this.recoveryInterval) {
427
- clearInterval(this.recoveryInterval);
428
- this.recoveryInterval = null;
429
- console.log('[BatchTaskQueue] Recovery mechanism stopped');
430
- }
431
- }
432
- /**
433
- * 启动消费者(内部方法,自动调用)
434
- */
435
- startConsumer() {
436
- if (this.consumerRunning || !this.redis) {
437
- return;
438
- }
439
- this.consumerRunning = true;
440
- console.log(`[BatchTaskQueue] Consumer started with batchSize: ${this.config.batchSize}`);
441
- // Lua 脚本: 原子化从 pending 取出任务并移到 processing(只取已到延迟时间的任务)
442
- const popAndMoveScript = `
443
- local pendingQueue = KEYS[1]
444
- local processingQueue = KEYS[2]
445
- local queueKeyPrefix = KEYS[3]
446
- local count = tonumber(ARGV[1])
447
- local currentTime = tonumber(ARGV[2])
448
-
449
- local taskIds = {}
450
- local checkedCount = 0
451
- local maxCheck = count * 3 -- 最多检查 count*3 个任务,避免无限循环
452
-
453
- while #taskIds < count and checkedCount < maxCheck do
454
- local taskId = redis.call('LPOP', pendingQueue)
455
- if not taskId then
456
- break
457
- end
458
-
459
- checkedCount = checkedCount + 1
460
-
461
- -- 获取任务详情检查延迟时间
462
- local taskKey = queueKeyPrefix .. ':task:' .. taskId
463
- local taskData = redis.call('GET', taskKey)
464
-
465
- if taskData then
466
- local task = cjson.decode(taskData)
467
- local delayUntil = task.delayUntil
468
-
469
- -- 如果没有延迟或已到延迟时间,则移到 processing
470
- if not delayUntil or delayUntil <= currentTime then
471
- redis.call('RPUSH', processingQueue, taskId)
472
- table.insert(taskIds, taskId)
473
- else
474
- -- 未到延迟时间,放回队列尾部
475
- redis.call('RPUSH', pendingQueue, taskId)
476
- end
477
- end
478
- end
479
-
480
- return taskIds
481
- `;
482
- this.consumerInterval = setInterval(async () => {
483
- try {
484
- // 检查是否有正在处理的批次(批量队列通常不需要并发控制,一次处理一批)
485
- if (this.processingBatches > 0) {
486
- return;
487
- }
488
- // 使用 Lua 脚本原子化取出任务并移到 processing 队列
489
- const taskIds = await this.redis.eval(popAndMoveScript, {
490
- keys: [this.pendingQueue, this.processingQueue, this.config.queueKey],
491
- arguments: [this.config.batchSize.toString(), Date.now().toString()],
492
- });
493
- if (taskIds.length > 0) {
494
- // 批量处理任务(不等待完成)
495
- this.processBatch(taskIds).catch(error => {
496
- console.error(`[BatchTaskQueue] Unhandled error in processBatch`, error);
497
- });
498
- }
499
- }
500
- catch (error) {
501
- console.error('[BatchTaskQueue] Consumer error:', error);
502
- }
503
- }, this.config.consumerInterval);
504
- }
505
- /**
506
- * 停止消费者(内部方法,自动调用)
507
- */
508
- stopConsumer() {
509
- if (this.consumerInterval) {
510
- clearInterval(this.consumerInterval);
511
- this.consumerInterval = null;
512
- }
513
- this.consumerRunning = false;
514
- console.log('[BatchTaskQueue] Consumer stopped');
515
- }
516
- /**
517
- * 获取队列统计信息
518
- * 返回队列中各种状态任务的详细数量
519
- *
520
- * 使用分离队列设计,O(1) 时间复杂度
521
- */
522
- async statistics() {
523
- if (!this.redis) {
524
- return {
525
- failed: 0,
526
- pending: 0,
527
- completed: 0,
528
- processing: 0,
529
- };
530
- }
531
- // 并行获取各队列长度,O(1) 时间复杂度
532
- const [pending, processing, completed, failed] = await Promise.all([
533
- this.redis.lLen(this.pendingQueue),
534
- this.redis.lLen(this.processingQueue),
535
- this.redis.lLen(this.completedQueue),
536
- this.redis.lLen(this.failedQueue),
537
- ]);
538
- return {
539
- pending,
540
- processing,
541
- completed,
542
- failed,
543
- };
544
- }
545
- /**
546
- * 清空所有队列
547
- */
548
- async clear() {
549
- if (!this.redis)
550
- return;
551
- // 使用 Lua 脚本原子化清空所有队列
552
- const clearScript = `
553
- redis.call('DEL', KEYS[1])
554
- redis.call('DEL', KEYS[2])
555
- redis.call('DEL', KEYS[3])
556
- redis.call('DEL', KEYS[4])
557
- return 1
558
- `;
559
- await this.redis.eval(clearScript, {
560
- keys: [this.failedQueue, this.pendingQueue, this.completedQueue, this.processingQueue],
561
- arguments: [],
562
- });
563
- }
564
- /**
565
- * 健康检查
566
- */
567
- async health() {
568
- if (!this.redis)
569
- return false;
570
- const result = await catchIt(() => this.redis.ping());
571
- return !result.isError() && result.value === 'PONG';
572
- }
573
- }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=batch-redis-queue.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"batch-redis-queue.test.d.ts","sourceRoot":"","sources":["../../source/redis-queue/batch-redis-queue.test.ts"],"names":[],"mappings":""}