@faapi/task-bullmq 6.3.0 → 6.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -1
- package/dist/index.js +95 -21
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -28,7 +28,7 @@ interface BullMQDriverOptions {
|
|
|
28
28
|
* 语义映射(详见包根 README):
|
|
29
29
|
* - `enqueue` → `queue.add(name, payload, { delay, attempts, backoff })`(每任务一个 Queue)
|
|
30
30
|
* - `startWorker` → `new Worker(name, handler, { connection, concurrency })`
|
|
31
|
-
* - `stop` → workers.close() + queues.close()(等 in-flight
|
|
31
|
+
* - `stop` → workers.close() + queues.close()(等 in-flight;超时 abort 在跑任务的 signal)
|
|
32
32
|
* - 重试 → BullMQ 侧执行(attempts = retries + 1,指数退避 500ms 起)
|
|
33
33
|
*/
|
|
34
34
|
declare function createBullMQDriver(options: BullMQDriverOptions): TaskDriver;
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,7 @@ function createBullMQDriver(options) {
|
|
|
8
8
|
let stopped = false;
|
|
9
9
|
const queues = /* @__PURE__ */ new Map();
|
|
10
10
|
const workers = /* @__PURE__ */ new Map();
|
|
11
|
+
const inflight = /* @__PURE__ */ new Map();
|
|
11
12
|
function getQueue(name) {
|
|
12
13
|
let q = queues.get(name);
|
|
13
14
|
if (!q) {
|
|
@@ -27,6 +28,8 @@ function createBullMQDriver(options) {
|
|
|
27
28
|
// BullMQ attempts 含首次执行,retries 是额外重试次数
|
|
28
29
|
attempts: (opts?.retries ?? 0) + 1,
|
|
29
30
|
backoff: { type: "exponential", delay: 500 },
|
|
31
|
+
// dedupId 幂等键:同 jobId 的 job 存活期内 add 被忽略(BullMQ 原生去重)
|
|
32
|
+
...opts?.dedupId ? { jobId: opts.dedupId } : {},
|
|
30
33
|
...opts?.delayMs ? { delay: opts.delayMs } : {}
|
|
31
34
|
});
|
|
32
35
|
return job.id ?? crypto.randomUUID();
|
|
@@ -40,16 +43,22 @@ function createBullMQDriver(options) {
|
|
|
40
43
|
const worker = new Worker(
|
|
41
44
|
name,
|
|
42
45
|
async (job) => {
|
|
43
|
-
const
|
|
44
|
-
attemptCounts.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
46
|
+
const id = job.id ?? "";
|
|
47
|
+
const attempt = (attemptCounts.get(id) ?? 0) + 1;
|
|
48
|
+
attemptCounts.set(id, attempt);
|
|
49
|
+
const controller = new AbortController();
|
|
50
|
+
inflight.set(id, controller);
|
|
51
|
+
try {
|
|
52
|
+
return await process({
|
|
53
|
+
id,
|
|
54
|
+
name,
|
|
55
|
+
payload: job.data,
|
|
56
|
+
attempt,
|
|
57
|
+
signal: controller.signal
|
|
58
|
+
});
|
|
59
|
+
} finally {
|
|
60
|
+
inflight.delete(id);
|
|
61
|
+
}
|
|
53
62
|
},
|
|
54
63
|
{ connection: options.connection, concurrency: workerOpts.concurrency, prefix }
|
|
55
64
|
);
|
|
@@ -60,22 +69,87 @@ function createBullMQDriver(options) {
|
|
|
60
69
|
},
|
|
61
70
|
async stop(timeoutMs = 1e4) {
|
|
62
71
|
stopped = true;
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
const abortTimer = setTimeout(() => {
|
|
73
|
+
for (const controller of inflight.values()) controller.abort();
|
|
74
|
+
}, timeoutMs);
|
|
75
|
+
try {
|
|
76
|
+
const closes = [
|
|
77
|
+
...Array.from(workers.values()).map((w) => w.close()),
|
|
78
|
+
...Array.from(queues.values()).map((q) => q.close())
|
|
79
|
+
];
|
|
80
|
+
workers.clear();
|
|
81
|
+
const timeout = new Promise((resolve) => {
|
|
82
|
+
const timer = setTimeout(resolve, timeoutMs);
|
|
83
|
+
timer.unref?.();
|
|
84
|
+
});
|
|
85
|
+
await Promise.race([Promise.all(closes), timeout]);
|
|
86
|
+
} finally {
|
|
87
|
+
clearTimeout(abortTimer);
|
|
88
|
+
for (const controller of inflight.values()) controller.abort();
|
|
89
|
+
inflight.clear();
|
|
90
|
+
attemptCounts.clear();
|
|
91
|
+
}
|
|
74
92
|
},
|
|
75
93
|
async stopWorkers() {
|
|
76
94
|
const closes = Array.from(workers.values()).map((w) => w.close());
|
|
77
95
|
workers.clear();
|
|
78
96
|
await Promise.all(closes);
|
|
97
|
+
},
|
|
98
|
+
async list(opts) {
|
|
99
|
+
const limit = opts?.limit ?? 50;
|
|
100
|
+
const targets = opts?.name ? [getQueue(opts.name)] : [...queues.values()];
|
|
101
|
+
const stateTypes = {
|
|
102
|
+
pending: ["waiting", "delayed"],
|
|
103
|
+
running: ["active"],
|
|
104
|
+
done: ["completed"],
|
|
105
|
+
failed: ["failed"]
|
|
106
|
+
};
|
|
107
|
+
const wanted = (opts?.state ? [opts.state] : ["pending", "running", "done", "failed"]).filter(
|
|
108
|
+
(s) => (stateTypes[s]?.length ?? 0) > 0
|
|
109
|
+
);
|
|
110
|
+
const records = [];
|
|
111
|
+
for (const status of wanted) {
|
|
112
|
+
const types = stateTypes[status];
|
|
113
|
+
for (const queue of targets) {
|
|
114
|
+
const jobs = await queue.getJobs(types, 0, limit - 1);
|
|
115
|
+
for (const job of jobs) {
|
|
116
|
+
if (!job) continue;
|
|
117
|
+
records.push({
|
|
118
|
+
id: job.id ?? "",
|
|
119
|
+
name: job.name,
|
|
120
|
+
payload: job.data,
|
|
121
|
+
status,
|
|
122
|
+
attempts: job.attemptsMade ?? 0,
|
|
123
|
+
...job.returnvalue !== void 0 && job.returnvalue !== null ? { result: job.returnvalue } : {},
|
|
124
|
+
...job.failedReason ? { error: job.failedReason } : {},
|
|
125
|
+
createdAt: job.timestamp,
|
|
126
|
+
...job.processedOn ? { runAt: job.processedOn } : {}
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return records.sort((a, b) => b.createdAt - a.createdAt).slice(0, limit);
|
|
132
|
+
},
|
|
133
|
+
async cancel(name, id) {
|
|
134
|
+
if (stopped) {
|
|
135
|
+
throw new Error(
|
|
136
|
+
"[faapi] Task queue is stopped and no longer accepts management operations"
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
const job = await getQueue(name).getJob(id);
|
|
140
|
+
if (job) await job.remove();
|
|
141
|
+
},
|
|
142
|
+
async retry(name, id) {
|
|
143
|
+
if (stopped) {
|
|
144
|
+
throw new Error(
|
|
145
|
+
"[faapi] Task queue is stopped and no longer accepts management operations"
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
const job = await getQueue(name).getJob(id);
|
|
149
|
+
if (!job) {
|
|
150
|
+
throw new Error(`[faapi] Task "${name}" job "${id}" not found`);
|
|
151
|
+
}
|
|
152
|
+
await job.retry();
|
|
79
153
|
}
|
|
80
154
|
};
|
|
81
155
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { TaskDriver, TaskDriverProcess } from '@faapi/faapi';\nimport { Queue, Worker, type ConnectionOptions, type Job } from 'bullmq';\n\n/**\n * BullMQ 驱动选项\n */\nexport interface BullMQDriverOptions {\n /** Redis 连接配置(透传给 Queue / Worker 的 connection) */\n connection: ConnectionOptions;\n /** 队列名前缀(默认 `faapi`——同一 Redis 下多个 faapi 应用隔离用) */\n prefix?: string;\n}\n\n/**\n * faapi 任务队列 BullMQ 驱动(Redis 持久化队列)\n *\n * 与 faapi 主包 `config.task.driver: 'bullmq'` 配合使用:\n *\n * ```ts\n * // faapi.config.ts\n * export default {\n * task: {\n * driver: 'bullmq',\n * bullmq: { connection: { host: '127.0.0.1', port: 6379 } },\n * },\n * } satisfies FaapiConfig;\n * ```\n *\n * 语义映射(详见包根 README):\n * - `enqueue` → `queue.add(name, payload, { delay, attempts, backoff })`(每任务一个 Queue)\n * - `startWorker` → `new Worker(name, handler, { connection, concurrency })`\n * - `stop` → workers.close() + queues.close()(等 in-flight;超时由 BullMQ 处置)\n * - 重试 → BullMQ 侧执行(attempts = retries + 1,指数退避 500ms 起)\n */\nexport function createBullMQDriver(options: BullMQDriverOptions): TaskDriver {\n if (!options?.connection) {\n throw new Error('[faapi] @faapi/task-bullmq requires `bullmq.connection` in config.task');\n }\n const prefix = options.prefix ?? 'faapi';\n\n let stopped = false;\n /** 每任务一个 Queue(按名缓存) */\n const queues = new Map<string, Queue>();\n /** 已创建的 Worker(stopWorkers / stop 时关闭) */\n const workers = new Map<string, Worker>();\n\n function getQueue(name: string): Queue {\n let q = queues.get(name);\n if (!q) {\n q = new Queue(name, { connection: options.connection, prefix });\n queues.set(name, q);\n }\n return q;\n }\n\n /** 驱动侧 attempt 计数(兼容不同 BullMQ 版本的 attemptsMade/attemptsStarted 字段差异) */\n const attemptCounts = new Map<string, number>();\n\n return {\n async enqueue(name, payload, opts) {\n if (stopped) {\n throw new Error('[faapi] Task queue is stopped and no longer accepts jobs');\n }\n const queue = getQueue(name);\n const job = await queue.add(name, payload, {\n // BullMQ attempts 含首次执行,retries 是额外重试次数\n attempts: (opts?.retries ?? 0) + 1,\n backoff: { type: 'exponential', delay: 500 },\n ...(opts?.delayMs ? { delay: opts.delayMs } : {}),\n });\n return job.id ?? crypto.randomUUID();\n },\n\n async startWorker(name, workerOpts) {\n const process: TaskDriverProcess = workerOpts.process;\n // 二次注册(reload 场景)先关旧 Worker\n const existing = workers.get(name);\n if (existing) {\n await existing.close();\n }\n const worker = new Worker(\n name,\n async (job: Job) => {\n const attempt = (attemptCounts.get(job.id ?? '') ?? 0) + 1;\n attemptCounts.set(job.id ?? '', attempt);\n return await process({\n id: job.id ?? '',\n name,\n payload: job.data,\n attempt,\n signal: new AbortController().signal, // BullMQ 不提供执行中任务的取消信号\n });\n },\n { connection: options.connection, concurrency: workerOpts.concurrency, prefix },\n );\n // 处理器内部异常已由语义层包装记录;这里兜底防止 unhandled error 事件崩进程\n worker.on('error', (err) => {\n console.error(`[faapi] bullmq worker error for task \"${name}\":`, err);\n });\n workers.set(name, worker);\n },\n\n async stop(timeoutMs = 10_000) {\n stopped = true;\n const closes = [\n ...Array.from(workers.values()).map((w) => w.close()),\n ...Array.from(queues.values()).map((q) => q.close()),\n ];\n workers.clear();\n const timeout = new Promise<void>((resolve) => {\n const timer = setTimeout(resolve, timeoutMs);\n timer.unref?.();\n });\n await Promise.race([Promise.all(closes), timeout]);\n attemptCounts.clear();\n },\n\n async stopWorkers() {\n const closes = Array.from(workers.values()).map((w) => w.close());\n workers.clear();\n await Promise.all(closes);\n },\n };\n}\n"],"mappings":";AACA,SAAS,OAAO,cAAgD;AAiCzD,SAAS,mBAAmB,SAA0C;AAC3E,MAAI,CAAC,SAAS,YAAY;AACxB,UAAM,IAAI,MAAM,wEAAwE;AAAA,EAC1F;AACA,QAAM,SAAS,QAAQ,UAAU;AAEjC,MAAI,UAAU;AAEd,QAAM,SAAS,oBAAI,IAAmB;AAEtC,QAAM,UAAU,oBAAI,IAAoB;AAExC,WAAS,SAAS,MAAqB;AACrC,QAAI,IAAI,OAAO,IAAI,IAAI;AACvB,QAAI,CAAC,GAAG;AACN,UAAI,IAAI,MAAM,MAAM,EAAE,YAAY,QAAQ,YAAY,OAAO,CAAC;AAC9D,aAAO,IAAI,MAAM,CAAC;AAAA,IACpB;AACA,WAAO;AAAA,EACT;AAGA,QAAM,gBAAgB,oBAAI,IAAoB;AAE9C,SAAO;AAAA,IACL,MAAM,QAAQ,MAAM,SAAS,MAAM;AACjC,UAAI,SAAS;AACX,cAAM,IAAI,MAAM,0DAA0D;AAAA,MAC5E;AACA,YAAM,QAAQ,SAAS,IAAI;AAC3B,YAAM,MAAM,MAAM,MAAM,IAAI,MAAM,SAAS;AAAA;AAAA,QAEzC,WAAW,MAAM,WAAW,KAAK;AAAA,QACjC,SAAS,EAAE,MAAM,eAAe,OAAO,IAAI;AAAA,QAC3C,GAAI,MAAM,UAAU,EAAE,OAAO,KAAK,QAAQ,IAAI,CAAC;AAAA,MACjD,CAAC;AACD,aAAO,IAAI,MAAM,OAAO,WAAW;AAAA,IACrC;AAAA,IAEA,MAAM,YAAY,MAAM,YAAY;AAClC,YAAM,UAA6B,WAAW;AAE9C,YAAM,WAAW,QAAQ,IAAI,IAAI;AACjC,UAAI,UAAU;AACZ,cAAM,SAAS,MAAM;AAAA,MACvB;AACA,YAAM,SAAS,IAAI;AAAA,QACjB;AAAA,QACA,OAAO,QAAa;AAClB,gBAAM,WAAW,cAAc,IAAI,IAAI,MAAM,EAAE,KAAK,KAAK;AACzD,wBAAc,IAAI,IAAI,MAAM,IAAI,OAAO;AACvC,iBAAO,MAAM,QAAQ;AAAA,YACnB,IAAI,IAAI,MAAM;AAAA,YACd;AAAA,YACA,SAAS,IAAI;AAAA,YACb;AAAA,YACA,QAAQ,IAAI,gBAAgB,EAAE;AAAA;AAAA,UAChC,CAAC;AAAA,QACH;AAAA,QACA,EAAE,YAAY,QAAQ,YAAY,aAAa,WAAW,aAAa,OAAO;AAAA,MAChF;AAEA,aAAO,GAAG,SAAS,CAAC,QAAQ;AAC1B,gBAAQ,MAAM,yCAAyC,IAAI,MAAM,GAAG;AAAA,MACtE,CAAC;AACD,cAAQ,IAAI,MAAM,MAAM;AAAA,IAC1B;AAAA,IAEA,MAAM,KAAK,YAAY,KAAQ;AAC7B,gBAAU;AACV,YAAM,SAAS;AAAA,QACb,GAAG,MAAM,KAAK,QAAQ,OAAO,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC;AAAA,QACpD,GAAG,MAAM,KAAK,OAAO,OAAO,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC;AAAA,MACrD;AACA,cAAQ,MAAM;AACd,YAAM,UAAU,IAAI,QAAc,CAAC,YAAY;AAC7C,cAAM,QAAQ,WAAW,SAAS,SAAS;AAC3C,cAAM,QAAQ;AAAA,MAChB,CAAC;AACD,YAAM,QAAQ,KAAK,CAAC,QAAQ,IAAI,MAAM,GAAG,OAAO,CAAC;AACjD,oBAAc,MAAM;AAAA,IACtB;AAAA,IAEA,MAAM,cAAc;AAClB,YAAM,SAAS,MAAM,KAAK,QAAQ,OAAO,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC;AAChE,cAAQ,MAAM;AACd,YAAM,QAAQ,IAAI,MAAM;AAAA,IAC1B;AAAA,EACF;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { TaskDriver, TaskDriverProcess, TaskDriverRecord, TaskJobStatus } from '@faapi/faapi';\nimport { Queue, Worker, type ConnectionOptions, type Job, type JobType } from 'bullmq';\n\n/**\n * BullMQ 驱动选项\n */\nexport interface BullMQDriverOptions {\n /** Redis 连接配置(透传给 Queue / Worker 的 connection) */\n connection: ConnectionOptions;\n /** 队列名前缀(默认 `faapi`——同一 Redis 下多个 faapi 应用隔离用) */\n prefix?: string;\n}\n\n/**\n * faapi 任务队列 BullMQ 驱动(Redis 持久化队列)\n *\n * 与 faapi 主包 `config.task.driver: 'bullmq'` 配合使用:\n *\n * ```ts\n * // faapi.config.ts\n * export default {\n * task: {\n * driver: 'bullmq',\n * bullmq: { connection: { host: '127.0.0.1', port: 6379 } },\n * },\n * } satisfies FaapiConfig;\n * ```\n *\n * 语义映射(详见包根 README):\n * - `enqueue` → `queue.add(name, payload, { delay, attempts, backoff })`(每任务一个 Queue)\n * - `startWorker` → `new Worker(name, handler, { connection, concurrency })`\n * - `stop` → workers.close() + queues.close()(等 in-flight;超时 abort 在跑任务的 signal)\n * - 重试 → BullMQ 侧执行(attempts = retries + 1,指数退避 500ms 起)\n */\nexport function createBullMQDriver(options: BullMQDriverOptions): TaskDriver {\n if (!options?.connection) {\n throw new Error('[faapi] @faapi/task-bullmq requires `bullmq.connection` in config.task');\n }\n const prefix = options.prefix ?? 'faapi';\n\n let stopped = false;\n /** 每任务一个 Queue(按名缓存) */\n const queues = new Map<string, Queue>();\n /** 已创建的 Worker(stopWorkers / stop 时关闭) */\n const workers = new Map<string, Worker>();\n /** 在跑任务的取消控制器(stop 超时 abort——run 监听 signal 可尽快退出) */\n const inflight = new Map<string, AbortController>();\n\n function getQueue(name: string): Queue {\n let q = queues.get(name);\n if (!q) {\n q = new Queue(name, { connection: options.connection, prefix });\n queues.set(name, q);\n }\n return q;\n }\n\n /** 驱动侧 attempt 计数(兼容不同 BullMQ 版本的 attemptsMade/attemptsStarted 字段差异) */\n const attemptCounts = new Map<string, number>();\n\n return {\n async enqueue(name, payload, opts) {\n if (stopped) {\n throw new Error('[faapi] Task queue is stopped and no longer accepts jobs');\n }\n const queue = getQueue(name);\n const job = await queue.add(name, payload, {\n // BullMQ attempts 含首次执行,retries 是额外重试次数\n attempts: (opts?.retries ?? 0) + 1,\n backoff: { type: 'exponential', delay: 500 },\n // dedupId 幂等键:同 jobId 的 job 存活期内 add 被忽略(BullMQ 原生去重)\n ...(opts?.dedupId ? { jobId: opts.dedupId } : {}),\n ...(opts?.delayMs ? { delay: opts.delayMs } : {}),\n });\n return job.id ?? crypto.randomUUID();\n },\n\n async startWorker(name, workerOpts) {\n const process: TaskDriverProcess = workerOpts.process;\n // 二次注册(reload 场景)先关旧 Worker\n const existing = workers.get(name);\n if (existing) {\n await existing.close();\n }\n const worker = new Worker(\n name,\n async (job: Job) => {\n const id = job.id ?? '';\n const attempt = (attemptCounts.get(id) ?? 0) + 1;\n attemptCounts.set(id, attempt);\n // 信号由驱动自管:stop 超时 abort(BullMQ 自身不提供执行中任务的取消能力)\n const controller = new AbortController();\n inflight.set(id, controller);\n try {\n return await process({\n id,\n name,\n payload: job.data,\n attempt,\n signal: controller.signal,\n });\n } finally {\n inflight.delete(id);\n }\n },\n { connection: options.connection, concurrency: workerOpts.concurrency, prefix },\n );\n // 处理器内部异常已由语义层包装记录;这里兜底防止 unhandled error 事件崩进程\n worker.on('error', (err) => {\n console.error(`[faapi] bullmq worker error for task \"${name}\":`, err);\n });\n workers.set(name, worker);\n },\n\n async stop(timeoutMs = 10_000) {\n stopped = true;\n // 等待超时到点 abort 在跑任务(run 监听 signal 尽快退出);等待结束后兜底 abort 残留\n const abortTimer = setTimeout(() => {\n for (const controller of inflight.values()) controller.abort();\n }, timeoutMs);\n try {\n const closes = [\n ...Array.from(workers.values()).map((w) => w.close()),\n ...Array.from(queues.values()).map((q) => q.close()),\n ];\n workers.clear();\n const timeout = new Promise<void>((resolve) => {\n const timer = setTimeout(resolve, timeoutMs);\n timer.unref?.();\n });\n await Promise.race([Promise.all(closes), timeout]);\n } finally {\n clearTimeout(abortTimer);\n for (const controller of inflight.values()) controller.abort();\n inflight.clear();\n attemptCounts.clear();\n }\n },\n\n async stopWorkers() {\n const closes = Array.from(workers.values()).map((w) => w.close());\n workers.clear();\n await Promise.all(closes);\n },\n\n async list(opts) {\n const limit = opts?.limit ?? 50;\n // 目标队列:指定 name 时按需创建 Queue 实例;不传时遍历本进程已创建的\n // (BullMQ 队列按 Redis key 寻址,额外实例不影响驱动内的队列)\n const targets: Queue[] = opts?.name ? [getQueue(opts.name)] : [...queues.values()];\n // faapi 语义状态 → BullMQ JobType 分组(cancel 为 job.remove,无 cancelled 可查;\n // 重试等待中的 job 处于 delayed → 归入 pending)\n const stateTypes: Partial<Record<TaskJobStatus, JobType[]>> = {\n pending: ['waiting', 'delayed'],\n running: ['active'],\n done: ['completed'],\n failed: ['failed'],\n };\n const wanted = (opts?.state ? [opts.state] : ['pending', 'running', 'done', 'failed']).filter(\n (s): s is TaskJobStatus => (stateTypes[s as TaskJobStatus]?.length ?? 0) > 0,\n );\n\n const records: TaskDriverRecord[] = [];\n for (const status of wanted) {\n const types = stateTypes[status]!;\n for (const queue of targets) {\n const jobs = await queue.getJobs(types, 0, limit - 1);\n for (const job of jobs) {\n if (!job) continue;\n records.push({\n id: job.id ?? '',\n name: job.name,\n payload: job.data,\n status,\n attempts: job.attemptsMade ?? 0,\n ...(job.returnvalue !== undefined && job.returnvalue !== null\n ? { result: job.returnvalue }\n : {}),\n ...(job.failedReason ? { error: job.failedReason } : {}),\n createdAt: job.timestamp,\n ...(job.processedOn ? { runAt: job.processedOn } : {}),\n });\n }\n }\n }\n return records.sort((a, b) => b.createdAt - a.createdAt).slice(0, limit);\n },\n\n async cancel(name, id) {\n if (stopped) {\n throw new Error(\n '[faapi] Task queue is stopped and no longer accepts management operations',\n );\n }\n // BullMQ 无 cancelled 状态——取消即移除(等待/延迟中的不再执行;active 受锁限制由 BullMQ 抛错)\n const job = await getQueue(name).getJob(id);\n if (job) await job.remove();\n },\n\n async retry(name, id) {\n if (stopped) {\n throw new Error(\n '[faapi] Task queue is stopped and no longer accepts management operations',\n );\n }\n const job = await getQueue(name).getJob(id);\n if (!job) {\n throw new Error(`[faapi] Task \"${name}\" job \"${id}\" not found`);\n }\n await job.retry(); // 仅 failed 可重试;其余状态由 BullMQ 抛错\n },\n };\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faapi/task-bullmq",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.4.0",
|
|
4
4
|
"description": "BullMQ task queue driver for faapi — persistent queue on Redis",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -24,11 +24,11 @@
|
|
|
24
24
|
"tsup": "^8.4.0",
|
|
25
25
|
"typescript": "^5.7.0",
|
|
26
26
|
"vitest": "^4.1.11",
|
|
27
|
-
"@faapi/faapi": "6.
|
|
27
|
+
"@faapi/faapi": "6.4.0"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
30
|
"bullmq": "^5.0.0",
|
|
31
|
-
"@faapi/faapi": "^6.
|
|
31
|
+
"@faapi/faapi": "^6.4.0"
|
|
32
32
|
},
|
|
33
33
|
"license": "MIT",
|
|
34
34
|
"repository": {
|