@taicode/common-server 3.0.1 → 3.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/output/context/index.d.ts +6 -0
- package/output/context/index.d.ts.map +1 -0
- package/output/context/index.js +14 -0
- package/output/context/index.test.d.ts +2 -0
- package/output/context/index.test.d.ts.map +1 -0
- package/output/context/index.test.js +14 -0
- package/output/index.d.ts +4 -2
- package/output/index.d.ts.map +1 -1
- package/output/index.js +4 -2
- package/output/rate-limiter/index.d.ts +4 -0
- package/output/rate-limiter/index.d.ts.map +1 -0
- package/output/rate-limiter/index.js +3 -0
- package/output/rate-limiter/memory-store.d.ts +12 -0
- package/output/rate-limiter/memory-store.d.ts.map +1 -0
- package/output/rate-limiter/memory-store.js +46 -0
- package/output/rate-limiter/rate-limiter.d.ts +17 -0
- package/output/rate-limiter/rate-limiter.d.ts.map +1 -0
- package/output/rate-limiter/rate-limiter.js +64 -0
- package/output/rate-limiter/types.d.ts +27 -0
- package/output/rate-limiter/types.d.ts.map +1 -0
- package/output/rate-limiter/types.js +1 -0
- package/output/redis-queue/index.d.ts +7 -7
- package/output/redis-queue/index.d.ts.map +1 -1
- package/output/redis-queue/index.js +4 -4
- package/output/redis-queue/redis-queue-batch-consumer.d.ts +3 -3
- package/output/redis-queue/redis-queue-batch-consumer.d.ts.map +1 -1
- package/output/redis-queue/redis-queue-batch-consumer.js +19 -18
- package/output/redis-queue/redis-queue-batch-consumer.test.d.ts +1 -1
- package/output/redis-queue/redis-queue-batch-consumer.test.d.ts.map +1 -1
- package/output/redis-queue/redis-queue-batch-consumer.test.js +3 -3
- package/output/redis-queue/redis-queue-common.d.ts +2 -2
- package/output/redis-queue/redis-queue-common.d.ts.map +1 -1
- package/output/redis-queue/redis-queue-common.js +5 -4
- package/output/redis-queue/redis-queue-common.test.d.ts +1 -1
- package/output/redis-queue/redis-queue-common.test.d.ts.map +1 -1
- package/output/redis-queue/redis-queue-common.test.js +1 -1
- package/output/redis-queue/redis-queue-consumer.d.ts +3 -3
- package/output/redis-queue/redis-queue-consumer.d.ts.map +1 -1
- package/output/redis-queue/redis-queue-consumer.js +19 -18
- package/output/redis-queue/redis-queue-consumer.test.d.ts +1 -1
- package/output/redis-queue/redis-queue-consumer.test.d.ts.map +1 -1
- package/output/redis-queue/redis-queue-consumer.test.js +3 -3
- package/output/redis-queue/redis-queue-provider.d.ts +2 -2
- package/output/redis-queue/redis-queue-provider.d.ts.map +1 -1
- package/output/redis-queue/redis-queue-provider.js +6 -5
- package/output/redis-queue/redis-queue-provider.test.d.ts +1 -1
- package/output/redis-queue/redis-queue-provider.test.d.ts.map +1 -1
- package/output/redis-queue/redis-queue-provider.test.js +2 -2
- package/output/redis-queue/test-helpers.d.ts +4 -4
- package/output/redis-queue/test-helpers.d.ts.map +1 -1
- package/output/redis-queue/test-helpers.js +1 -1
- package/output/redis-queue/test-helpers.test.d.ts +1 -1
- package/output/redis-queue/test-helpers.test.d.ts.map +1 -1
- package/output/redis-queue/test-helpers.test.js +4 -4
- package/output/redis-queue/types.d.ts +1 -1
- package/output/redis-queue/types.d.ts.map +1 -1
- package/output/schema/index.d.ts +1 -1
- package/output/schema/index.d.ts.map +1 -1
- package/output/schema/index.js +1 -1
- package/package.json +15 -13
- package/output/redis-queue/redis-batch-consumer.d.ts +0 -89
- package/output/redis-queue/redis-batch-consumer.d.ts.map +0 -1
- package/output/redis-queue/redis-batch-consumer.js +0 -371
- package/output/redis-queue/redis-batch-consumer.test.d.ts +0 -7
- package/output/redis-queue/redis-batch-consumer.test.d.ts.map +0 -1
- package/output/redis-queue/redis-batch-consumer.test.js +0 -265
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/context/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAEhE,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,iBAAiB,CAAA;CACvB;AAcD,wBAAgB,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,cAAc,CAErE"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const fallbackLogger = {
|
|
2
|
+
trace: () => { },
|
|
3
|
+
debug: () => { },
|
|
4
|
+
info: () => { },
|
|
5
|
+
warn: () => { },
|
|
6
|
+
error: () => { },
|
|
7
|
+
fatal: () => { },
|
|
8
|
+
child: () => fallbackLogger,
|
|
9
|
+
level: 'info',
|
|
10
|
+
silent: () => { },
|
|
11
|
+
};
|
|
12
|
+
export function createContext(request) {
|
|
13
|
+
return { log: request.log || fallbackLogger };
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../source/context/index.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { createContext } from './index.js';
|
|
3
|
+
describe('createContext', () => {
|
|
4
|
+
it('uses the request logger when one is available', () => {
|
|
5
|
+
const log = { info: () => { } };
|
|
6
|
+
const context = createContext({ log });
|
|
7
|
+
expect(context.log).toBe(log);
|
|
8
|
+
});
|
|
9
|
+
it('provides a fallback logger for lightweight test requests', () => {
|
|
10
|
+
const context = createContext({ log: undefined });
|
|
11
|
+
expect(context.log.level).toBe('info');
|
|
12
|
+
expect(() => context.log.info('message')).not.toThrow();
|
|
13
|
+
});
|
|
14
|
+
});
|
package/output/index.d.ts
CHANGED
package/output/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../source/index.ts"],"names":[],"mappings":"AACA,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../source/index.ts"],"names":[],"mappings":"AACA,cAAc,mBAAmB,CAAA;AACjC,cAAc,wBAAwB,CAAA;AACtC,cAAc,yBAAyB,CAAA;AACvC,cAAc,oBAAoB,CAAA"}
|
package/output/index.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/rate-limiter/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { RateLimitInfo, RateLimitStore } from './types.js';
|
|
2
|
+
export declare class MemoryRateLimitStore implements RateLimitStore {
|
|
3
|
+
private store;
|
|
4
|
+
private cleanupInterval;
|
|
5
|
+
constructor(cleanupIntervalMs?: number);
|
|
6
|
+
get(key: string): Promise<RateLimitInfo | null>;
|
|
7
|
+
set(key: string, info: RateLimitInfo): Promise<void>;
|
|
8
|
+
delete(key: string): Promise<void>;
|
|
9
|
+
cleanup(): Promise<void>;
|
|
10
|
+
destroy(): void;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=memory-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-store.d.ts","sourceRoot":"","sources":["../../source/rate-limiter/memory-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAO/D,qBAAa,oBAAqB,YAAW,cAAc;IACzD,OAAO,CAAC,KAAK,CAAsC;IACnD,OAAO,CAAC,eAAe,CAA8B;gBAEzC,iBAAiB,SAAQ;IAY/B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAY/C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAKpD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAS9B,OAAO,IAAI,IAAI;CAOhB"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export class MemoryRateLimitStore {
|
|
2
|
+
store = new Map();
|
|
3
|
+
cleanupInterval = null;
|
|
4
|
+
constructor(cleanupIntervalMs = 60000) {
|
|
5
|
+
// 定期清理过期数据
|
|
6
|
+
this.cleanupInterval = setInterval(() => {
|
|
7
|
+
this.cleanup();
|
|
8
|
+
}, cleanupIntervalMs);
|
|
9
|
+
// 防止内存泄漏
|
|
10
|
+
if (this.cleanupInterval.unref) {
|
|
11
|
+
this.cleanupInterval.unref();
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
async get(key) {
|
|
15
|
+
const entry = this.store.get(key);
|
|
16
|
+
if (!entry)
|
|
17
|
+
return null;
|
|
18
|
+
if (Date.now() > entry.expiresAt) {
|
|
19
|
+
this.store.delete(key);
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
return entry.info;
|
|
23
|
+
}
|
|
24
|
+
async set(key, info) {
|
|
25
|
+
const expiresAt = info.windowEnd.getTime();
|
|
26
|
+
this.store.set(key, { info, expiresAt });
|
|
27
|
+
}
|
|
28
|
+
async delete(key) {
|
|
29
|
+
this.store.delete(key);
|
|
30
|
+
}
|
|
31
|
+
async cleanup() {
|
|
32
|
+
const now = Date.now();
|
|
33
|
+
for (const [key, entry] of this.store.entries()) {
|
|
34
|
+
if (now > entry.expiresAt) {
|
|
35
|
+
this.store.delete(key);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
destroy() {
|
|
40
|
+
if (this.cleanupInterval) {
|
|
41
|
+
clearInterval(this.cleanupInterval);
|
|
42
|
+
this.cleanupInterval = null;
|
|
43
|
+
}
|
|
44
|
+
this.store.clear();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { RateLimitConfig, RateLimitInfo, RateLimiterOptions, RateLimitResult } from './types.js';
|
|
2
|
+
export declare class RateLimiter {
|
|
3
|
+
private store;
|
|
4
|
+
constructor(options?: RateLimiterOptions);
|
|
5
|
+
checkLimit(key: string, config: RateLimitConfig): Promise<RateLimitResult>;
|
|
6
|
+
resetLimit(key: string): Promise<void>;
|
|
7
|
+
getLimitInfo(key: string): Promise<RateLimitInfo | null>;
|
|
8
|
+
/**
|
|
9
|
+
* 检查多个限流键,取最严格的限制
|
|
10
|
+
*/
|
|
11
|
+
checkMultiLimit(keys: string[], config: RateLimitConfig): Promise<RateLimitResult>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 创建限流键的辅助函数
|
|
15
|
+
*/
|
|
16
|
+
export declare function createRateLimitKey(prefix: string, ...parts: string[]): string;
|
|
17
|
+
//# sourceMappingURL=rate-limiter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../source/rate-limiter/rate-limiter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,kBAAkB,EAAE,eAAe,EAAkB,MAAM,YAAY,CAAA;AAGrH,qBAAa,WAAW;IACtB,OAAO,CAAC,KAAK,CAAgB;gBAEjB,OAAO,GAAE,kBAAuB;IAItC,UAAU,CACd,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC,eAAe,CAAC;IAoCrB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAItC,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAI9D;;OAEG;IACG,eAAe,CACnB,IAAI,EAAE,MAAM,EAAE,EACd,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC,eAAe,CAAC;CAe5B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAE7E"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { MemoryRateLimitStore } from './memory-store.js';
|
|
2
|
+
export class RateLimiter {
|
|
3
|
+
store;
|
|
4
|
+
constructor(options = {}) {
|
|
5
|
+
this.store = options.store || new MemoryRateLimitStore();
|
|
6
|
+
}
|
|
7
|
+
async checkLimit(key, config) {
|
|
8
|
+
const now = new Date();
|
|
9
|
+
const windowStart = new Date(now.getTime());
|
|
10
|
+
const windowEnd = new Date(now.getTime() + config.window * 1000);
|
|
11
|
+
// 获取当前计数
|
|
12
|
+
let currentInfo = await this.store.get(key);
|
|
13
|
+
// 如果没有记录,或者窗口已过期,创建新记录
|
|
14
|
+
if (!currentInfo || currentInfo.windowEnd < now) {
|
|
15
|
+
currentInfo = {
|
|
16
|
+
count: 0,
|
|
17
|
+
windowStart,
|
|
18
|
+
windowEnd,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
// 增加计数
|
|
22
|
+
currentInfo.count += 1;
|
|
23
|
+
// 保存到存储
|
|
24
|
+
await this.store.set(key, currentInfo);
|
|
25
|
+
// 计算是否允许
|
|
26
|
+
const allowed = currentInfo.count <= config.limit;
|
|
27
|
+
const remaining = Math.max(0, config.limit - currentInfo.count);
|
|
28
|
+
return {
|
|
29
|
+
allowed,
|
|
30
|
+
remaining,
|
|
31
|
+
resetAt: currentInfo.windowEnd,
|
|
32
|
+
limit: config.limit,
|
|
33
|
+
window: config.window,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
async resetLimit(key) {
|
|
37
|
+
await this.store.delete(key);
|
|
38
|
+
}
|
|
39
|
+
async getLimitInfo(key) {
|
|
40
|
+
return await this.store.get(key);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 检查多个限流键,取最严格的限制
|
|
44
|
+
*/
|
|
45
|
+
async checkMultiLimit(keys, config) {
|
|
46
|
+
let strictestResult = null;
|
|
47
|
+
for (const key of keys) {
|
|
48
|
+
const result = await this.checkLimit(key, config);
|
|
49
|
+
if (!strictestResult || !result.allowed) {
|
|
50
|
+
strictestResult = result;
|
|
51
|
+
}
|
|
52
|
+
else if (result.remaining < strictestResult.remaining) {
|
|
53
|
+
strictestResult = result;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return strictestResult;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* 创建限流键的辅助函数
|
|
61
|
+
*/
|
|
62
|
+
export function createRateLimitKey(prefix, ...parts) {
|
|
63
|
+
return `rate-limit:${prefix}:${parts.join(':')}`;
|
|
64
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface RateLimitInfo {
|
|
2
|
+
count: number;
|
|
3
|
+
windowStart: Date;
|
|
4
|
+
windowEnd: Date;
|
|
5
|
+
}
|
|
6
|
+
export interface RateLimitResult {
|
|
7
|
+
allowed: boolean;
|
|
8
|
+
remaining: number;
|
|
9
|
+
resetAt: Date;
|
|
10
|
+
limit: number;
|
|
11
|
+
window: number;
|
|
12
|
+
}
|
|
13
|
+
export interface RateLimitStore {
|
|
14
|
+
get(key: string): Promise<RateLimitInfo | null>;
|
|
15
|
+
set(key: string, info: RateLimitInfo): Promise<void>;
|
|
16
|
+
delete(key: string): Promise<void>;
|
|
17
|
+
cleanup?(): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
export interface RateLimitConfig {
|
|
20
|
+
limit: number;
|
|
21
|
+
window: number;
|
|
22
|
+
lockout?: number;
|
|
23
|
+
}
|
|
24
|
+
export interface RateLimiterOptions {
|
|
25
|
+
store?: RateLimitStore;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../source/rate-limiter/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,IAAI,CAAA;IACjB,SAAS,EAAE,IAAI,CAAA;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,IAAI,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAA;IAC/C,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACpD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAClC,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,cAAc,CAAA;CACvB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export { RedisQueueProvider } from './redis-queue-provider';
|
|
2
|
-
export { RedisQueueConsumer } from './redis-queue-consumer';
|
|
3
|
-
export { RedisQueueBatchConsumer } from './redis-queue-batch-consumer';
|
|
4
|
-
export type { RedisQueueProviderConfig, RedisQueueConsumerConfig, BatchConsumerConfig } from './types';
|
|
5
|
-
export type { TaskData } from './types';
|
|
6
|
-
export type { RedisQueueRegistry } from './types';
|
|
7
|
-
export * as test from './test-helpers';
|
|
1
|
+
export { RedisQueueProvider } from './redis-queue-provider.js';
|
|
2
|
+
export { RedisQueueConsumer } from './redis-queue-consumer.js';
|
|
3
|
+
export { RedisQueueBatchConsumer } from './redis-queue-batch-consumer.js';
|
|
4
|
+
export type { RedisQueueProviderConfig, RedisQueueConsumerConfig, BatchConsumerConfig } from './types.js';
|
|
5
|
+
export type { TaskData } from './types.js';
|
|
6
|
+
export type { RedisQueueRegistry } from './types.js';
|
|
7
|
+
export * as test from './test-helpers.js';
|
|
8
8
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/redis-queue/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/redis-queue/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA;AAC9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAA;AAGzE,YAAY,EAAE,wBAAwB,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAGzG,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAG1C,YAAY,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAGpD,OAAO,KAAK,IAAI,MAAM,mBAAmB,CAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// 核心类导出
|
|
2
|
-
export { RedisQueueProvider } from './redis-queue-provider';
|
|
3
|
-
export { RedisQueueConsumer } from './redis-queue-consumer';
|
|
4
|
-
export { RedisQueueBatchConsumer } from './redis-queue-batch-consumer';
|
|
2
|
+
export { RedisQueueProvider } from './redis-queue-provider.js';
|
|
3
|
+
export { RedisQueueConsumer } from './redis-queue-consumer.js';
|
|
4
|
+
export { RedisQueueBatchConsumer } from './redis-queue-batch-consumer.js';
|
|
5
5
|
// 测试辅助函数导出
|
|
6
|
-
export * as test from './test-helpers';
|
|
6
|
+
export * as test from './test-helpers.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { RedisQueueCommon } from './redis-queue-common';
|
|
2
|
-
import type { BatchConsumerConfig, QueueStats, RedisQueueRegistry } from './types';
|
|
1
|
+
import { RedisQueueCommon } from './redis-queue-common.js';
|
|
2
|
+
import type { BatchConsumerConfig, QueueStats, RedisQueueRegistry } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Redis 批量队列消费者
|
|
5
5
|
*
|
|
@@ -32,7 +32,7 @@ import type { BatchConsumerConfig, QueueStats, RedisQueueRegistry } from './type
|
|
|
32
32
|
* batchSize: 50,
|
|
33
33
|
* handler: async (dataList) => {
|
|
34
34
|
* const total = dataList.reduce((sum, d) => sum + d.amount, 0)
|
|
35
|
-
*
|
|
35
|
+
* logger.info('Total amount:', total)
|
|
36
36
|
* return catchIt(() => {})
|
|
37
37
|
* }
|
|
38
38
|
* }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redis-queue-batch-consumer.d.ts","sourceRoot":"","sources":["../../source/redis-queue/redis-queue-batch-consumer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"redis-queue-batch-consumer.d.ts","sourceRoot":"","sources":["../../source/redis-queue/redis-queue-batch-consumer.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,KAAK,EAAE,mBAAmB,EAA0B,UAAU,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAE7G;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,qBAAa,uBAAuB,CAClC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,kBAAkB,EAClD,CAAC,SAAS,MAAM,CAAC,GAAG,MAAM,GAAG,MAAM,CAAC,GAAG,MAAM,CAC7C,SAAQ,gBAAgB;IACxB,OAAO,CAAC,eAAe,CAAQ;IAC/B,OAAO,CAAC,gBAAgB,CAA8B;IACtD,OAAO,CAAC,gBAAgB,CAA8B;IACtD,OAAO,CAAC,iBAAiB,CAAI;IAC7B,OAAO,CAAC,kBAAkB,CAA2B;IAErD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAOtB;gBAEW,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAuB1D,SAAS,CAAC,YAAY,IAAI,MAAM;IAIhC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAO9B;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAgBjC;;OAEG;YACW,YAAY;IA2G1B;;OAEG;IACH,OAAO,CAAC,aAAa;IAoBrB;;OAEG;IACH,OAAO,CAAC,YAAY;IAQpB;;OAEG;IACH,OAAO,CAAC,aAAa;IAyErB;;OAEG;IACH,OAAO,CAAC,YAAY;IASpB;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,UAAU,CAAC;IAevC;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;CAMjC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { catchIt } from '@taicode/common-base';
|
|
2
|
-
import {
|
|
2
|
+
import { logger } from '@taicode/common-base';
|
|
3
|
+
import { RedisQueueCommon } from './redis-queue-common.js';
|
|
3
4
|
/**
|
|
4
5
|
* Redis 批量队列消费者
|
|
5
6
|
*
|
|
@@ -32,7 +33,7 @@ import { RedisQueueCommon } from './redis-queue-common';
|
|
|
32
33
|
* batchSize: 50,
|
|
33
34
|
* handler: async (dataList) => {
|
|
34
35
|
* const total = dataList.reduce((sum, d) => sum + d.amount, 0)
|
|
35
|
-
*
|
|
36
|
+
* logger.info('Total amount:', total)
|
|
36
37
|
* return catchIt(() => {})
|
|
37
38
|
* }
|
|
38
39
|
* }
|
|
@@ -96,9 +97,9 @@ export class RedisQueueBatchConsumer extends RedisQueueCommon {
|
|
|
96
97
|
this.stopRecovery();
|
|
97
98
|
// 等待所有正在处理的批次完成
|
|
98
99
|
if (this.processingPromises.size > 0) {
|
|
99
|
-
|
|
100
|
+
logger.info(`[RedisQueueBatchConsumer] Waiting for ${this.processingPromises.size} batches to complete...`);
|
|
100
101
|
await Promise.allSettled(this.processingPromises);
|
|
101
|
-
|
|
102
|
+
logger.info(`[RedisQueueBatchConsumer] All batches completed`);
|
|
102
103
|
}
|
|
103
104
|
// 最后断开 Redis 连接
|
|
104
105
|
super.disconnect();
|
|
@@ -115,7 +116,7 @@ export class RedisQueueBatchConsumer extends RedisQueueCommon {
|
|
|
115
116
|
const tasks = await Promise.all(taskIds.map(id => this.getTask(id)));
|
|
116
117
|
const validTasks = tasks.filter((task) => task !== null);
|
|
117
118
|
if (validTasks.length === 0) {
|
|
118
|
-
|
|
119
|
+
logger.warn(`[RedisQueueBatchConsumer] No valid tasks found in batch`);
|
|
119
120
|
return;
|
|
120
121
|
}
|
|
121
122
|
// 过滤出有效的待处理任务
|
|
@@ -123,7 +124,7 @@ export class RedisQueueBatchConsumer extends RedisQueueCommon {
|
|
|
123
124
|
for (const task of validTasks) {
|
|
124
125
|
// 检查状态
|
|
125
126
|
if (task.status !== 'pending') {
|
|
126
|
-
|
|
127
|
+
logger.info(`[RedisQueueBatchConsumer] Task ${task.id} has invalid status (${task.status}), marking as failed`);
|
|
127
128
|
await this.applyStatus(task.id, task.status, 'failed');
|
|
128
129
|
continue;
|
|
129
130
|
}
|
|
@@ -147,10 +148,10 @@ export class RedisQueueBatchConsumer extends RedisQueueCommon {
|
|
|
147
148
|
await this.config.handler(dataList);
|
|
148
149
|
// 批量更新状态为完成
|
|
149
150
|
const updatedCount = await this.applyStatusBatch(taskIdList, 'processing', 'completed');
|
|
150
|
-
|
|
151
|
+
logger.info(`[RedisQueueBatchConsumer] Batch completed: ${updatedCount} tasks`);
|
|
151
152
|
}
|
|
152
153
|
catch (error) {
|
|
153
|
-
|
|
154
|
+
logger.error(`[RedisQueueBatchConsumer] Batch failed:`, error);
|
|
154
155
|
// 批量重试或失败
|
|
155
156
|
for (const task of tasksToProcess) {
|
|
156
157
|
if (task.retryCount < task.maxRetries) {
|
|
@@ -168,7 +169,7 @@ export class RedisQueueBatchConsumer extends RedisQueueCommon {
|
|
|
168
169
|
keys: [taskKey, this.processingQueue, this.pendingQueue],
|
|
169
170
|
arguments: [this.cleanupDelay.toString(), JSON.stringify(task), task.id],
|
|
170
171
|
});
|
|
171
|
-
|
|
172
|
+
logger.info(`[RedisQueueBatchConsumer] Task ${task.id} will retry (${task.retryCount}/${task.maxRetries})`);
|
|
172
173
|
}
|
|
173
174
|
else {
|
|
174
175
|
task.status = 'failed';
|
|
@@ -184,7 +185,7 @@ export class RedisQueueBatchConsumer extends RedisQueueCommon {
|
|
|
184
185
|
keys: [taskKey, this.processingQueue, this.failedQueue],
|
|
185
186
|
arguments: [this.cleanupDelay.toString(), JSON.stringify(task), task.id],
|
|
186
187
|
});
|
|
187
|
-
|
|
188
|
+
logger.error(`[RedisQueueBatchConsumer] Task ${task.id} failed after ${task.maxRetries} retries`);
|
|
188
189
|
}
|
|
189
190
|
}
|
|
190
191
|
}
|
|
@@ -211,15 +212,15 @@ export class RedisQueueBatchConsumer extends RedisQueueCommon {
|
|
|
211
212
|
}
|
|
212
213
|
// 立即执行一次恢复
|
|
213
214
|
this.recoverStalled(this.config.processingTimeout).catch(error => {
|
|
214
|
-
|
|
215
|
+
logger.error('[RedisQueueBatchConsumer] Initial recovery error:', error);
|
|
215
216
|
});
|
|
216
217
|
// 定期检查(每 10 秒检查一次)
|
|
217
218
|
this.recoveryInterval = setInterval(() => {
|
|
218
219
|
this.recoverStalled(this.config.processingTimeout).catch(error => {
|
|
219
|
-
|
|
220
|
+
logger.error('[RedisQueueBatchConsumer] Recovery error:', error);
|
|
220
221
|
});
|
|
221
222
|
}, 10000);
|
|
222
|
-
|
|
223
|
+
logger.info('[RedisQueueBatchConsumer] Recovery mechanism started');
|
|
223
224
|
}
|
|
224
225
|
/**
|
|
225
226
|
* 停止恢复机制
|
|
@@ -228,7 +229,7 @@ export class RedisQueueBatchConsumer extends RedisQueueCommon {
|
|
|
228
229
|
if (this.recoveryInterval) {
|
|
229
230
|
clearInterval(this.recoveryInterval);
|
|
230
231
|
this.recoveryInterval = null;
|
|
231
|
-
|
|
232
|
+
logger.info('[RedisQueueBatchConsumer] Recovery mechanism stopped');
|
|
232
233
|
}
|
|
233
234
|
}
|
|
234
235
|
/**
|
|
@@ -239,7 +240,7 @@ export class RedisQueueBatchConsumer extends RedisQueueCommon {
|
|
|
239
240
|
return;
|
|
240
241
|
}
|
|
241
242
|
this.consumerRunning = true;
|
|
242
|
-
|
|
243
|
+
logger.info(`[RedisQueueBatchConsumer] Consumer started with batchSize: ${this.config.batchSize}, concurrency: ${this.config.concurrency}`);
|
|
243
244
|
// Lua 脚本: 批量原子化从 pending 取出任务并移到 processing
|
|
244
245
|
const popAndMoveBatchScript = `
|
|
245
246
|
local pendingQueue = KEYS[1]
|
|
@@ -293,12 +294,12 @@ export class RedisQueueBatchConsumer extends RedisQueueCommon {
|
|
|
293
294
|
if (taskIds.length > 0) {
|
|
294
295
|
// 处理这批任务(不等待完成)
|
|
295
296
|
this.processBatch(taskIds).catch(error => {
|
|
296
|
-
|
|
297
|
+
logger.error(`[RedisQueueBatchConsumer] Unhandled error in processBatch:`, error);
|
|
297
298
|
});
|
|
298
299
|
}
|
|
299
300
|
}
|
|
300
301
|
catch (error) {
|
|
301
|
-
|
|
302
|
+
logger.error('[RedisQueueBatchConsumer] Consumer error:', error);
|
|
302
303
|
}
|
|
303
304
|
}, this.config.consumerInterval);
|
|
304
305
|
}
|
|
@@ -311,7 +312,7 @@ export class RedisQueueBatchConsumer extends RedisQueueCommon {
|
|
|
311
312
|
this.consumerInterval = null;
|
|
312
313
|
}
|
|
313
314
|
this.consumerRunning = false;
|
|
314
|
-
|
|
315
|
+
logger.info('[RedisQueueBatchConsumer] Consumer stopped');
|
|
315
316
|
}
|
|
316
317
|
/**
|
|
317
318
|
* 获取队列统计信息(O(1) 时间复杂度)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redis-queue-batch-consumer.test.d.ts","sourceRoot":"","sources":["../../source/redis-queue/redis-queue-batch-consumer.test.ts"],"names":[],"mappings":"AAQA,KAAK,YAAY,GAAG;IAClB,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACvB,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;IACvB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,GAAG,CAAA;CACX,CAAA;AAGD,OAAO,QAAQ,
|
|
1
|
+
{"version":3,"file":"redis-queue-batch-consumer.test.d.ts","sourceRoot":"","sources":["../../source/redis-queue/redis-queue-batch-consumer.test.ts"],"names":[],"mappings":"AAQA,KAAK,YAAY,GAAG;IAClB,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACvB,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;IACvB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,GAAG,CAAA;CACX,CAAA;AAGD,OAAO,QAAQ,YAAY,CAAC;IAC1B,UAAU,kBAAkB;QAC1B,CAAC,GAAG,EAAE,cAAc,MAAM,EAAE,GAAG,YAAY,CAAA;KAC5C;CACF"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { describe, it, expect, afterEach } from 'vitest';
|
|
2
2
|
import { catchIt } from '@taicode/common-base';
|
|
3
|
-
import { RedisQueueProvider } from './redis-queue-provider';
|
|
4
|
-
import { RedisQueueBatchConsumer } from './redis-queue-batch-consumer';
|
|
5
|
-
import { dispatchQueueTask, waitQueueCompletion, clearQueue, getQueueTasks } from './test-helpers';
|
|
3
|
+
import { RedisQueueProvider } from './redis-queue-provider.js';
|
|
4
|
+
import { RedisQueueBatchConsumer } from './redis-queue-batch-consumer.js';
|
|
5
|
+
import { dispatchQueueTask, waitQueueCompletion, clearQueue, getQueueTasks } from './test-helpers.js';
|
|
6
6
|
const REDIS_URL = process.env.REDIS_URL || 'redis://localhost:6379';
|
|
7
7
|
describe('RedisQueueBatchConsumer', () => {
|
|
8
8
|
const providers = [];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { RedisClientType } from 'redis';
|
|
2
|
-
import type { Status, Task, RedisQueueCommonConfig } from './types';
|
|
1
|
+
import { type RedisClientType } from 'redis';
|
|
2
|
+
import type { Status, Task, RedisQueueCommonConfig } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Redis 队列基础类
|
|
5
5
|
* 封装 Provider 和 Consumer 的公共逻辑
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redis-queue-common.d.ts","sourceRoot":"","sources":["../../source/redis-queue/redis-queue-common.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,eAAe,EAAE,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"redis-queue-common.d.ts","sourceRoot":"","sources":["../../source/redis-queue/redis-queue-common.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,eAAe,EAAE,MAAM,OAAO,CAAA;AAE1D,OAAO,KAAK,EAAE,MAAM,EAAY,IAAI,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAEhF;;;GAGG;AACH,8BAAsB,gBAAgB;IACpC,SAAS,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,CAAO;IAC9C,SAAS,CAAC,eAAe,EAAE,OAAO,CAAQ;IAE1C,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACnC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACpC,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAGvC,SAAS,CAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IACtC,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IACvC,SAAS,CAAC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAC1C,SAAS,CAAC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;gBAE7B,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAE,sBAA2B;IAwCjE;;OAEG;IACH,SAAS,CAAC,QAAQ,CAAC,YAAY,IAAI,MAAM;IAEzC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAS9B;;OAEG;IACH,UAAU,IAAI,IAAI;IAalB;;OAEG;cACa,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAW7D;;OAEG;IACH,SAAS,CAAC,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAUlD;;OAEG;cACa,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqChG;;;OAGG;cACa,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAqD1G;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAevG;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;IAUhC;;;;;;;OAOG;cACa,cAAc,CAAC,iBAAiB,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CA4E/G"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createClient } from 'redis';
|
|
2
|
+
import { logger } from '@taicode/common-base';
|
|
2
3
|
/**
|
|
3
4
|
* Redis 队列基础类
|
|
4
5
|
* 封装 Provider 和 Consumer 的公共逻辑
|
|
@@ -46,7 +47,7 @@ export class RedisQueueCommon {
|
|
|
46
47
|
this.isExternalRedis = false;
|
|
47
48
|
// 添加错误处理
|
|
48
49
|
this.redis.on('error', (err) => {
|
|
49
|
-
|
|
50
|
+
logger.error(`[${this.getLogPrefix()}] Redis Client Error:`, err);
|
|
50
51
|
});
|
|
51
52
|
}
|
|
52
53
|
}
|
|
@@ -56,7 +57,7 @@ export class RedisQueueCommon {
|
|
|
56
57
|
async connect() {
|
|
57
58
|
if (this.redis && !this.redis.isOpen) {
|
|
58
59
|
await this.redis.connect().catch((error) => {
|
|
59
|
-
|
|
60
|
+
logger.error(`[${this.getLogPrefix()}] Failed to connect to Redis:`, error);
|
|
60
61
|
throw error;
|
|
61
62
|
});
|
|
62
63
|
}
|
|
@@ -71,7 +72,7 @@ export class RedisQueueCommon {
|
|
|
71
72
|
}
|
|
72
73
|
if (this.redis && this.redis.isOpen) {
|
|
73
74
|
this.redis.disconnect().catch((error) => {
|
|
74
|
-
|
|
75
|
+
logger.error(`[${this.getLogPrefix()}] Failed to disconnect:`, error);
|
|
75
76
|
});
|
|
76
77
|
}
|
|
77
78
|
}
|
|
@@ -295,7 +296,7 @@ export class RedisQueueCommon {
|
|
|
295
296
|
}
|
|
296
297
|
catch (error) {
|
|
297
298
|
const logPrefix = this.getLogPrefix();
|
|
298
|
-
|
|
299
|
+
logger.error(`[${logPrefix}] Failed to recover stalled tasks:`, error);
|
|
299
300
|
return { timeoutFailed: 0, cleaned: 0 };
|
|
300
301
|
}
|
|
301
302
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redis-queue-common.test.d.ts","sourceRoot":"","sources":["../../source/redis-queue/redis-queue-common.test.ts"],"names":[],"mappings":"AAOA,OAAO,QAAQ,
|
|
1
|
+
{"version":3,"file":"redis-queue-common.test.d.ts","sourceRoot":"","sources":["../../source/redis-queue/redis-queue-common.test.ts"],"names":[],"mappings":"AAOA,OAAO,QAAQ,YAAY,CAAC;IAC1B,UAAU,kBAAkB;QAC1B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QACjC,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QACvC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QAC5B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QAChC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QACnC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QAClC,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QACvB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QAC/B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QACjC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QAC/B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QAChC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QAChC,CAAC,GAAG,EAAE,kBAAkB,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;KACvD;CACF"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
-
import { RedisQueueCommon } from './redis-queue-common';
|
|
2
|
+
import { RedisQueueCommon } from './redis-queue-common.js';
|
|
3
3
|
const REDIS_URL = process.env.REDIS_URL || 'redis://localhost:6379';
|
|
4
4
|
// 创建一个具体的测试类来测试抽象基类
|
|
5
5
|
class TestRedisQueueCommon extends RedisQueueCommon {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { RedisQueueCommon } from './redis-queue-common';
|
|
2
|
-
import type { RedisQueueConsumerConfig, RedisQueueRegistry, QueueStats } from './types';
|
|
1
|
+
import { RedisQueueCommon } from './redis-queue-common.js';
|
|
2
|
+
import type { RedisQueueConsumerConfig, RedisQueueRegistry, QueueStats } from './types.js';
|
|
3
3
|
/**
|
|
4
4
|
* Redis 队列消费者
|
|
5
5
|
*
|
|
@@ -30,7 +30,7 @@ import type { RedisQueueConsumerConfig, RedisQueueRegistry, QueueStats } from '.
|
|
|
30
30
|
* {
|
|
31
31
|
* redisUrl: 'redis://localhost:6379',
|
|
32
32
|
* handler: async (data) => {
|
|
33
|
-
*
|
|
33
|
+
* logger.info(data.orderId, data.amount)
|
|
34
34
|
* return catchIt(() => {})
|
|
35
35
|
* }
|
|
36
36
|
* }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redis-queue-consumer.d.ts","sourceRoot":"","sources":["../../source/redis-queue/redis-queue-consumer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"redis-queue-consumer.d.ts","sourceRoot":"","sources":["../../source/redis-queue/redis-queue-consumer.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,KAAK,EAAE,wBAAwB,EAAe,kBAAkB,EAAgB,UAAU,EAAE,MAAM,YAAY,CAAA;AAErH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,qBAAa,kBAAkB,CAC7B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,kBAAkB,EAClD,CAAC,SAAS,MAAM,CAAC,GAAG,MAAM,GAAG,MAAM,CAAC,GAAG,MAAM,CAC7C,SAAQ,gBAAgB;IACxB,OAAO,CAAC,eAAe,CAAQ;IAC/B,OAAO,CAAC,gBAAgB,CAA8B;IACtD,OAAO,CAAC,gBAAgB,CAA8B;IACtD,OAAO,CAAC,eAAe,CAAI;IAC3B,OAAO,CAAC,kBAAkB,CAA2B;IAErD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAOtB;gBAEW,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,wBAAwB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAuB/D,SAAS,CAAC,YAAY,IAAI,MAAM;IAIhC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAO9B;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAgBjC;;OAEG;YACW,WAAW;IA2FzB;;OAEG;IACH,OAAO,CAAC,aAAa;IAoBrB;;OAEG;IACH,OAAO,CAAC,YAAY;IAQpB;;OAEG;IACH,OAAO,CAAC,aAAa;IA4ErB;;OAEG;IACH,OAAO,CAAC,YAAY;IASpB;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,UAAU,CAAC;IAevC;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;CAMjC"}
|