@weifuwujs/tasks 0.9.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 +170 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +319 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/postgres.d.ts +3 -0
- package/dist/postgres.d.ts.map +1 -0
- package/dist/postgres.js +2 -0
- package/dist/postgres.js.map +1 -0
- package/dist/redis.d.ts +3 -0
- package/dist/redis.d.ts.map +1 -0
- package/dist/redis.js +2 -0
- package/dist/redis.js.map +1 -0
- package/dist/sqlite.d.ts +3 -0
- package/dist/sqlite.d.ts.map +1 -0
- package/dist/sqlite.js +2 -0
- package/dist/sqlite.js.map +1 -0
- package/dist/stores/memory.d.ts +6 -0
- package/dist/stores/memory.d.ts.map +1 -0
- package/dist/stores/memory.js +169 -0
- package/dist/stores/memory.js.map +1 -0
- package/dist/stores/postgres.d.ts +22 -0
- package/dist/stores/postgres.d.ts.map +1 -0
- package/dist/stores/postgres.js +233 -0
- package/dist/stores/postgres.js.map +1 -0
- package/dist/stores/redis.d.ts +21 -0
- package/dist/stores/redis.d.ts.map +1 -0
- package/dist/stores/redis.js +340 -0
- package/dist/stores/redis.js.map +1 -0
- package/dist/stores/sqlite.d.ts +13 -0
- package/dist/stores/sqlite.d.ts.map +1 -0
- package/dist/stores/sqlite.js +216 -0
- package/dist/stores/sqlite.js.map +1 -0
- package/dist/tasks.d.ts +11 -0
- package/dist/tasks.d.ts.map +1 -0
- package/dist/tasks.js +214 -0
- package/dist/tasks.js.map +1 -0
- package/dist/testing.d.ts +13 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +211 -0
- package/dist/testing.js.map +1 -0
- package/dist/types.d.ts +158 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +61 -0
package/dist/tasks.js
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
/**
|
|
3
|
+
* 任务队列:handler 注册在进程内,库里只存 `name + payload`。
|
|
4
|
+
*
|
|
5
|
+
* - 至少一次:claim → 执行 → complete;崩溃后锁过期自动回队重跑;
|
|
6
|
+
* - 未知 handler:不领取(保持 pending)并告警一次;改名遗留用 CLI `tasks prune`;
|
|
7
|
+
* - 周期任务 `every`:首次立即到期,完成后排下一次(宕机后 catch-up);
|
|
8
|
+
* - 注入时钟 + runOnce/drain:测试不 sleep。
|
|
9
|
+
*/
|
|
10
|
+
export function createTasks(options) {
|
|
11
|
+
const store = options.store;
|
|
12
|
+
const concurrency = Math.max(1, options.concurrency ?? 1);
|
|
13
|
+
const pollIntervalMs = Math.max(10, options.pollIntervalMs ?? 1000);
|
|
14
|
+
const warnAfterMs = options.warnAfterMs ?? 30_000;
|
|
15
|
+
const visibilityTimeoutMs = options.visibilityTimeoutMs ?? 60_000;
|
|
16
|
+
const baseMs = options.retry?.baseMs ?? 1000;
|
|
17
|
+
const maxMs = options.retry?.maxMs ?? 15 * 60_000;
|
|
18
|
+
const now = options.now ?? (() => new Date());
|
|
19
|
+
const workerId = options.workerId ?? `worker-${process.pid}-${randomUUID().slice(0, 8)}`;
|
|
20
|
+
const logger = options.logger ?? console;
|
|
21
|
+
const handlers = new Map();
|
|
22
|
+
const periodic = new Map();
|
|
23
|
+
const warnedUnknown = new Set();
|
|
24
|
+
const inFlight = new Map();
|
|
25
|
+
let timer = null;
|
|
26
|
+
let stopped = false;
|
|
27
|
+
let ticking = false;
|
|
28
|
+
const backoffMs = (attempt) => Math.min(baseMs * 2 ** Math.max(0, attempt - 1), maxMs);
|
|
29
|
+
async function ensureScheduled(name) {
|
|
30
|
+
const schedule = periodic.get(name);
|
|
31
|
+
if (!schedule)
|
|
32
|
+
return;
|
|
33
|
+
const active = await store.list({
|
|
34
|
+
name,
|
|
35
|
+
statuses: ['pending', 'running'],
|
|
36
|
+
limit: 1,
|
|
37
|
+
});
|
|
38
|
+
if (active.length > 0)
|
|
39
|
+
return;
|
|
40
|
+
await store.enqueue({
|
|
41
|
+
name,
|
|
42
|
+
payload: schedule.payload,
|
|
43
|
+
runAt: now(),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
async function warnUnknown() {
|
|
47
|
+
const names = await store.pendingNames(now());
|
|
48
|
+
for (const name of names) {
|
|
49
|
+
if (handlers.has(name) || warnedUnknown.has(name))
|
|
50
|
+
continue;
|
|
51
|
+
warnedUnknown.add(name);
|
|
52
|
+
logger.warn(`[tasks] 未注册 handler:${name}(保持 pending;注册后再执行,改名遗留可 tasks prune)`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async function execute(task) {
|
|
56
|
+
const handler = handlers.get(task.name);
|
|
57
|
+
if (!handler)
|
|
58
|
+
return;
|
|
59
|
+
const started = Date.now();
|
|
60
|
+
const ctx = {
|
|
61
|
+
id: task.id,
|
|
62
|
+
name: task.name,
|
|
63
|
+
attempt: task.attempts,
|
|
64
|
+
};
|
|
65
|
+
try {
|
|
66
|
+
await handler(task.payload, ctx);
|
|
67
|
+
const elapsed = Date.now() - started;
|
|
68
|
+
if (elapsed > warnAfterMs) {
|
|
69
|
+
logger.warn(`[tasks] ${task.name}#${task.id} 运行 ${elapsed}ms 超过 warnAfterMs=${warnAfterMs}(只告警不中断)`);
|
|
70
|
+
}
|
|
71
|
+
await store.complete(task.id, now());
|
|
72
|
+
const schedule = periodic.get(task.name);
|
|
73
|
+
if (schedule) {
|
|
74
|
+
await store.enqueue({
|
|
75
|
+
name: task.name,
|
|
76
|
+
payload: schedule.payload,
|
|
77
|
+
runAt: new Date(now().getTime() + schedule.intervalMs),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
83
|
+
if (task.attempts >= task.maxAttempts) {
|
|
84
|
+
await store.fail(task.id, { error: message, retryAt: null }, now());
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
await store.fail(task.id, {
|
|
88
|
+
error: message,
|
|
89
|
+
retryAt: new Date(now().getTime() + backoffMs(task.attempts)),
|
|
90
|
+
}, now());
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async function runOnce() {
|
|
95
|
+
for (const name of periodic.keys())
|
|
96
|
+
await ensureScheduled(name);
|
|
97
|
+
await warnUnknown();
|
|
98
|
+
const claimed = await store.claim({
|
|
99
|
+
now: now(),
|
|
100
|
+
workerId,
|
|
101
|
+
limit: concurrency,
|
|
102
|
+
visibilityTimeoutMs,
|
|
103
|
+
names: [...handlers.keys()],
|
|
104
|
+
});
|
|
105
|
+
if (claimed.length === 0)
|
|
106
|
+
return 0;
|
|
107
|
+
await Promise.all(claimed.map((task) => {
|
|
108
|
+
const promise = execute(task).finally(() => {
|
|
109
|
+
inFlight.delete(task.id);
|
|
110
|
+
});
|
|
111
|
+
inFlight.set(task.id, promise);
|
|
112
|
+
return promise;
|
|
113
|
+
}));
|
|
114
|
+
return claimed.length;
|
|
115
|
+
}
|
|
116
|
+
async function drain(drainOptions = {}) {
|
|
117
|
+
const maxIterations = drainOptions.maxIterations ?? 10_000;
|
|
118
|
+
for (let index = 0; index < maxIterations; index++) {
|
|
119
|
+
const count = await runOnce();
|
|
120
|
+
if (count === 0)
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
async function tick() {
|
|
125
|
+
if (ticking)
|
|
126
|
+
return;
|
|
127
|
+
ticking = true;
|
|
128
|
+
try {
|
|
129
|
+
await runOnce();
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
logger.error(`[tasks] 轮询失败:${error instanceof Error ? error.message : String(error)}`);
|
|
133
|
+
}
|
|
134
|
+
finally {
|
|
135
|
+
ticking = false;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
const api = {
|
|
139
|
+
store,
|
|
140
|
+
handle(name, handler) {
|
|
141
|
+
handlers.set(name, handler);
|
|
142
|
+
return api;
|
|
143
|
+
},
|
|
144
|
+
async enqueue(name, payload, enqueueOptions = {}) {
|
|
145
|
+
const runAt = enqueueOptions.runAt ??
|
|
146
|
+
new Date(now().getTime() + (enqueueOptions.delay ?? 0));
|
|
147
|
+
const result = await store.enqueue({
|
|
148
|
+
name,
|
|
149
|
+
payload,
|
|
150
|
+
runAt,
|
|
151
|
+
maxAttempts: enqueueOptions.maxAttempts,
|
|
152
|
+
idempotencyKey: enqueueOptions.idempotencyKey ?? null,
|
|
153
|
+
});
|
|
154
|
+
if (options.autoStart !== false && !timer && !stopped)
|
|
155
|
+
api.start();
|
|
156
|
+
return { id: result.task.id, created: result.created, task: result.task };
|
|
157
|
+
},
|
|
158
|
+
install(app, installOptions = {}) {
|
|
159
|
+
const timeoutMs = installOptions.timeoutMs ?? 5000;
|
|
160
|
+
app.onClose(() => api.stop({ timeoutMs }));
|
|
161
|
+
api.start();
|
|
162
|
+
return api;
|
|
163
|
+
},
|
|
164
|
+
every(name, intervalMs, payload) {
|
|
165
|
+
periodic.set(name, { intervalMs, payload: payload ?? null });
|
|
166
|
+
return api;
|
|
167
|
+
},
|
|
168
|
+
start() {
|
|
169
|
+
stopped = false;
|
|
170
|
+
if (timer)
|
|
171
|
+
return;
|
|
172
|
+
for (const name of periodic.keys()) {
|
|
173
|
+
void ensureScheduled(name).catch((error) => logger.error(String(error)));
|
|
174
|
+
}
|
|
175
|
+
timer = setInterval(() => {
|
|
176
|
+
void tick();
|
|
177
|
+
}, pollIntervalMs);
|
|
178
|
+
timer.unref?.();
|
|
179
|
+
void tick();
|
|
180
|
+
},
|
|
181
|
+
async stop(stopOptions = {}) {
|
|
182
|
+
stopped = true;
|
|
183
|
+
if (timer) {
|
|
184
|
+
clearInterval(timer);
|
|
185
|
+
timer = null;
|
|
186
|
+
}
|
|
187
|
+
if (inFlight.size === 0)
|
|
188
|
+
return;
|
|
189
|
+
const timeoutMs = stopOptions.timeoutMs ?? 5000;
|
|
190
|
+
const deadline = Date.now() + timeoutMs;
|
|
191
|
+
while (inFlight.size > 0 && Date.now() < deadline) {
|
|
192
|
+
await Promise.race([
|
|
193
|
+
Promise.all([...inFlight.values()]),
|
|
194
|
+
new Promise((resolve) => setTimeout(resolve, 20)),
|
|
195
|
+
]);
|
|
196
|
+
}
|
|
197
|
+
// 超时未完成:归还队列(继续跑完不阻塞进程,at-least-once 允许重跑)
|
|
198
|
+
if (inFlight.size > 0) {
|
|
199
|
+
for (const id of [...inFlight.keys()]) {
|
|
200
|
+
await store.release(id, now(), now());
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
runOnce,
|
|
205
|
+
drain,
|
|
206
|
+
retry: (id) => store.retry(id, now()),
|
|
207
|
+
list: (filter) => store.list(filter),
|
|
208
|
+
get running() {
|
|
209
|
+
return timer !== null;
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
return api;
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=tasks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tasks.js","sourceRoot":"","sources":["../src/tasks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { TaskStore } from './types.ts';
|
|
2
|
+
/**
|
|
3
|
+
* 任务存储契约套件:memory / sqlite / postgres / redis 与自定义驱动共用。
|
|
4
|
+
*
|
|
5
|
+
* ```ts
|
|
6
|
+
* import { tasksStoreContract } from '@weifuwujs/tasks/testing'
|
|
7
|
+
* tasksStoreContract('my-store', () => myTaskStore())
|
|
8
|
+
* ```
|
|
9
|
+
*/
|
|
10
|
+
export declare function tasksStoreContract(name: string, create: () => TaskStore | Promise<TaskStore>, options?: {
|
|
11
|
+
skip?: boolean | string;
|
|
12
|
+
}): void;
|
|
13
|
+
//# sourceMappingURL=testing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAI3C;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,EAC5C,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;CAAO,GACxC,IAAI,CAoON"}
|
package/dist/testing.js
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { describe, test } from 'node:test';
|
|
3
|
+
const T0 = new Date('2026-01-01T00:00:00.000Z');
|
|
4
|
+
/**
|
|
5
|
+
* 任务存储契约套件:memory / sqlite / postgres / redis 与自定义驱动共用。
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { tasksStoreContract } from '@weifuwujs/tasks/testing'
|
|
9
|
+
* tasksStoreContract('my-store', () => myTaskStore())
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
export function tasksStoreContract(name, create, options = {}) {
|
|
13
|
+
describe(`task store contract (${name})`, { skip: options.skip }, () => {
|
|
14
|
+
test('enqueue/get/幂等键', async () => {
|
|
15
|
+
const store = await create();
|
|
16
|
+
const first = await store.enqueue({
|
|
17
|
+
name: 'a',
|
|
18
|
+
payload: { n: 1 },
|
|
19
|
+
runAt: T0,
|
|
20
|
+
idempotencyKey: 'k-1',
|
|
21
|
+
});
|
|
22
|
+
assert.equal(first.created, true);
|
|
23
|
+
assert.equal(first.task.status, 'pending');
|
|
24
|
+
assert.equal(first.task.attempts, 0);
|
|
25
|
+
assert.equal(first.task.lockedBy, null);
|
|
26
|
+
assert.equal(first.task.maxAttempts, 5);
|
|
27
|
+
assert.deepEqual(first.task.payload, { n: 1 });
|
|
28
|
+
assert.deepEqual((await store.get(first.task.id))?.payload, { n: 1 });
|
|
29
|
+
const again = await store.enqueue({
|
|
30
|
+
name: 'a',
|
|
31
|
+
payload: { n: 2 },
|
|
32
|
+
runAt: T0,
|
|
33
|
+
idempotencyKey: 'k-1',
|
|
34
|
+
});
|
|
35
|
+
assert.equal(again.created, false);
|
|
36
|
+
assert.equal(again.task.id, first.task.id);
|
|
37
|
+
assert.deepEqual(again.task.payload, { n: 1 }, '幂等命中不得覆盖原任务');
|
|
38
|
+
const noKey = await store.enqueue({ name: 'a', runAt: T0 });
|
|
39
|
+
assert.equal(noKey.created, true);
|
|
40
|
+
assert.equal((await store.list()).length, 2);
|
|
41
|
+
assert.equal(await store.get('missing'), null);
|
|
42
|
+
assert.ok((await store.pendingNames(T0)).includes('a'));
|
|
43
|
+
});
|
|
44
|
+
test('claim:原子、attempts、names 过滤、锁过期回收', async () => {
|
|
45
|
+
const store = await create();
|
|
46
|
+
await store.enqueue({ name: 'a', runAt: T0 });
|
|
47
|
+
await store.enqueue({ name: 'a', runAt: T0 });
|
|
48
|
+
await store.enqueue({ name: 'b', runAt: T0 });
|
|
49
|
+
const claimed = await store.claim({
|
|
50
|
+
now: T0,
|
|
51
|
+
workerId: 'w1',
|
|
52
|
+
limit: 2,
|
|
53
|
+
visibilityTimeoutMs: 60_000,
|
|
54
|
+
});
|
|
55
|
+
assert.equal(claimed.length, 2);
|
|
56
|
+
for (const task of claimed) {
|
|
57
|
+
assert.equal(task.status, 'running');
|
|
58
|
+
assert.equal(task.lockedBy, 'w1');
|
|
59
|
+
assert.ok(task.lockedAt);
|
|
60
|
+
assert.equal(task.attempts, 1);
|
|
61
|
+
}
|
|
62
|
+
const second = await store.claim({
|
|
63
|
+
now: T0,
|
|
64
|
+
workerId: 'w2',
|
|
65
|
+
limit: 5,
|
|
66
|
+
visibilityTimeoutMs: 60_000,
|
|
67
|
+
});
|
|
68
|
+
assert.equal(second.length, 1, '同一任务不得双取');
|
|
69
|
+
await store.complete(claimed[0].id, T0);
|
|
70
|
+
assert.equal((await store.get(claimed[0].id))?.status, 'done');
|
|
71
|
+
const beforeExpiry = await store.claim({
|
|
72
|
+
now: new Date(T0.getTime() + 59_000),
|
|
73
|
+
workerId: 'w3',
|
|
74
|
+
limit: 5,
|
|
75
|
+
visibilityTimeoutMs: 60_000,
|
|
76
|
+
});
|
|
77
|
+
assert.equal(beforeExpiry.length, 0, '锁未过期不得重取');
|
|
78
|
+
const reclaimed = await store.claim({
|
|
79
|
+
now: new Date(T0.getTime() + 61_000),
|
|
80
|
+
workerId: 'w3',
|
|
81
|
+
limit: 5,
|
|
82
|
+
visibilityTimeoutMs: 60_000,
|
|
83
|
+
});
|
|
84
|
+
assert.equal(reclaimed.length, 2, '锁过期必须回队');
|
|
85
|
+
assert.equal(reclaimed[0].attempts, 2, '重领即第二次尝试');
|
|
86
|
+
assert.equal(reclaimed[0].lockedBy, 'w3');
|
|
87
|
+
const none = await store.claim({
|
|
88
|
+
now: new Date(T0.getTime() + 200_000),
|
|
89
|
+
workerId: 'w4',
|
|
90
|
+
limit: 5,
|
|
91
|
+
visibilityTimeoutMs: 60_000,
|
|
92
|
+
names: [],
|
|
93
|
+
});
|
|
94
|
+
assert.equal(none.length, 0, 'names 为空不得领取');
|
|
95
|
+
});
|
|
96
|
+
test('fail/retry/release:退避、死信、手动重驱', async () => {
|
|
97
|
+
const store = await create();
|
|
98
|
+
const { task } = await store.enqueue({
|
|
99
|
+
name: 'a',
|
|
100
|
+
runAt: T0,
|
|
101
|
+
maxAttempts: 2,
|
|
102
|
+
});
|
|
103
|
+
const [claimed] = await store.claim({
|
|
104
|
+
now: T0,
|
|
105
|
+
workerId: 'w',
|
|
106
|
+
limit: 1,
|
|
107
|
+
visibilityTimeoutMs: 60_000,
|
|
108
|
+
});
|
|
109
|
+
assert.equal(claimed.attempts, 1);
|
|
110
|
+
await store.fail(task.id, { error: 'boom-1', retryAt: new Date(T0.getTime() + 5000) }, T0);
|
|
111
|
+
let row = (await store.get(task.id));
|
|
112
|
+
assert.equal(row.status, 'pending');
|
|
113
|
+
assert.equal(row.lastError, 'boom-1');
|
|
114
|
+
assert.equal(row.runAt.getTime(), T0.getTime() + 5000);
|
|
115
|
+
assert.equal(row.lockedBy, null);
|
|
116
|
+
const notYet = await store.claim({
|
|
117
|
+
now: T0,
|
|
118
|
+
workerId: 'w',
|
|
119
|
+
limit: 1,
|
|
120
|
+
visibilityTimeoutMs: 60_000,
|
|
121
|
+
});
|
|
122
|
+
assert.equal(notYet.length, 0, '未到 retryAt 不得领取');
|
|
123
|
+
const [again] = await store.claim({
|
|
124
|
+
now: new Date(T0.getTime() + 5000),
|
|
125
|
+
workerId: 'w',
|
|
126
|
+
limit: 1,
|
|
127
|
+
visibilityTimeoutMs: 60_000,
|
|
128
|
+
});
|
|
129
|
+
assert.equal(again.attempts, 2);
|
|
130
|
+
await store.fail(task.id, { error: 'boom-2', retryAt: null }, T0);
|
|
131
|
+
row = (await store.get(task.id));
|
|
132
|
+
assert.equal(row.status, 'dead');
|
|
133
|
+
assert.equal(row.lastError, 'boom-2');
|
|
134
|
+
assert.equal(await store.retry(task.id, T0), true);
|
|
135
|
+
row = (await store.get(task.id));
|
|
136
|
+
assert.equal(row.status, 'pending');
|
|
137
|
+
assert.equal(row.attempts, 0, '手动重驱 attempts 归零');
|
|
138
|
+
assert.equal(await store.retry('missing', T0), false);
|
|
139
|
+
const released = await store.enqueue({ name: 'r', runAt: T0 });
|
|
140
|
+
const [claimedRelease] = await store.claim({
|
|
141
|
+
now: T0,
|
|
142
|
+
workerId: 'w',
|
|
143
|
+
limit: 1,
|
|
144
|
+
visibilityTimeoutMs: 60_000,
|
|
145
|
+
names: ['r'],
|
|
146
|
+
});
|
|
147
|
+
await store.release(claimedRelease.id, new Date(T0.getTime() + 1000), T0);
|
|
148
|
+
const releasedRow = (await store.get(released.task.id));
|
|
149
|
+
assert.equal(releasedRow.status, 'pending');
|
|
150
|
+
assert.equal(releasedRow.attempts, 1, 'release 保留 attempts');
|
|
151
|
+
assert.equal(releasedRow.runAt.getTime(), T0.getTime() + 1000);
|
|
152
|
+
});
|
|
153
|
+
test('硬崩溃:锁过期且 attempts 达上限 → dead,不无限重跑', async () => {
|
|
154
|
+
const store = await create();
|
|
155
|
+
const { task } = await store.enqueue({
|
|
156
|
+
name: 'a',
|
|
157
|
+
runAt: T0,
|
|
158
|
+
maxAttempts: 1,
|
|
159
|
+
});
|
|
160
|
+
await store.claim({
|
|
161
|
+
now: T0,
|
|
162
|
+
workerId: 'w',
|
|
163
|
+
limit: 1,
|
|
164
|
+
visibilityTimeoutMs: 60_000,
|
|
165
|
+
});
|
|
166
|
+
const reclaimed = await store.claim({
|
|
167
|
+
now: new Date(T0.getTime() + 61_000),
|
|
168
|
+
workerId: 'w2',
|
|
169
|
+
limit: 1,
|
|
170
|
+
visibilityTimeoutMs: 60_000,
|
|
171
|
+
});
|
|
172
|
+
assert.equal(reclaimed.length, 0);
|
|
173
|
+
const row = (await store.get(task.id));
|
|
174
|
+
assert.equal(row.status, 'dead');
|
|
175
|
+
assert.match(row.lastError ?? '', /visibility/i);
|
|
176
|
+
});
|
|
177
|
+
test('prune:清理 done/dead,不碰 pending', async () => {
|
|
178
|
+
const store = await create();
|
|
179
|
+
const done = await store.enqueue({ name: 'a', runAt: T0 });
|
|
180
|
+
await store.claim({
|
|
181
|
+
now: T0,
|
|
182
|
+
workerId: 'w',
|
|
183
|
+
limit: 1,
|
|
184
|
+
visibilityTimeoutMs: 60_000,
|
|
185
|
+
});
|
|
186
|
+
await store.complete(done.task.id, T0);
|
|
187
|
+
const dead = await store.enqueue({ name: 'b', runAt: T0 });
|
|
188
|
+
const [claimedDead] = await store.claim({
|
|
189
|
+
now: T0,
|
|
190
|
+
workerId: 'w',
|
|
191
|
+
limit: 1,
|
|
192
|
+
visibilityTimeoutMs: 60_000,
|
|
193
|
+
});
|
|
194
|
+
await store.fail(claimedDead.id, { error: 'dead', retryAt: null }, T0);
|
|
195
|
+
const pending = await store.enqueue({
|
|
196
|
+
name: 'c',
|
|
197
|
+
runAt: new Date(T0.getTime() + 10 * 60_000),
|
|
198
|
+
});
|
|
199
|
+
const removed = await store.prune({
|
|
200
|
+
now: new Date(T0.getTime() + 60_000),
|
|
201
|
+
olderThanMs: 30_000,
|
|
202
|
+
statuses: ['done', 'dead'],
|
|
203
|
+
});
|
|
204
|
+
assert.equal(removed, 2);
|
|
205
|
+
assert.equal(await store.get(done.task.id), null);
|
|
206
|
+
assert.equal(await store.get(dead.task.id), null);
|
|
207
|
+
assert.ok(await store.get(pending.task.id));
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=testing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.js","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/** 任务队列核心类型(驱动与执行器共用,四驱动契约一致) */
|
|
2
|
+
export type TaskStatus = 'pending' | 'running' | 'done' | 'dead';
|
|
3
|
+
export interface Task {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
/** 必须 JSON 可序列化(判负;驱动按此持久化) */
|
|
7
|
+
payload: unknown;
|
|
8
|
+
runAt: Date;
|
|
9
|
+
/** 已尝试次数(claim 即 +1,硬崩溃也会计入) */
|
|
10
|
+
attempts: number;
|
|
11
|
+
maxAttempts: number;
|
|
12
|
+
status: TaskStatus;
|
|
13
|
+
lockedBy: string | null;
|
|
14
|
+
lockedAt: Date | null;
|
|
15
|
+
/** 防重复入队;冲突时 enqueue 返回已有任务 */
|
|
16
|
+
idempotencyKey: string | null;
|
|
17
|
+
lastError: string | null;
|
|
18
|
+
createdAt: Date;
|
|
19
|
+
updatedAt: Date;
|
|
20
|
+
}
|
|
21
|
+
export interface EnqueueInput {
|
|
22
|
+
name: string;
|
|
23
|
+
payload?: unknown;
|
|
24
|
+
/** 默认立即到期 */
|
|
25
|
+
runAt?: Date;
|
|
26
|
+
maxAttempts?: number;
|
|
27
|
+
idempotencyKey?: string | null;
|
|
28
|
+
}
|
|
29
|
+
export interface EnqueueResult {
|
|
30
|
+
/** 任务 id(幂等命中时为已有任务) */
|
|
31
|
+
id: string;
|
|
32
|
+
/** false = 幂等键命中已有任务 */
|
|
33
|
+
created: boolean;
|
|
34
|
+
task: Task;
|
|
35
|
+
}
|
|
36
|
+
/** 驱动层返回(契约套件直接用) */
|
|
37
|
+
export interface StoreEnqueueResult {
|
|
38
|
+
task: Task;
|
|
39
|
+
created: boolean;
|
|
40
|
+
}
|
|
41
|
+
export interface ClaimOptions {
|
|
42
|
+
now: Date;
|
|
43
|
+
workerId: string;
|
|
44
|
+
limit: number;
|
|
45
|
+
/** 超过此时长仍 running 的任务回队(硬崩溃恢复) */
|
|
46
|
+
visibilityTimeoutMs: number;
|
|
47
|
+
/** 只领取这些 handler 名下的任务;不传 = 全部 */
|
|
48
|
+
names?: string[];
|
|
49
|
+
}
|
|
50
|
+
export interface FailInput {
|
|
51
|
+
error: string;
|
|
52
|
+
/** 下次运行时间;null = 进死信 */
|
|
53
|
+
retryAt: Date | null;
|
|
54
|
+
}
|
|
55
|
+
export interface ListFilter {
|
|
56
|
+
statuses?: TaskStatus[];
|
|
57
|
+
name?: string;
|
|
58
|
+
limit?: number;
|
|
59
|
+
}
|
|
60
|
+
export interface PruneOptions {
|
|
61
|
+
now: Date;
|
|
62
|
+
olderThanMs: number;
|
|
63
|
+
/** 默认 ['done', 'dead'] */
|
|
64
|
+
statuses?: TaskStatus[];
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 存储契约(memory / sqlite / postgres / redis 同一套)。
|
|
68
|
+
*
|
|
69
|
+
* 语义要点:
|
|
70
|
+
* - `claim` 原子且不双取;锁过期的 running 任务可被重领(attempts +1);
|
|
71
|
+
* 锁过期且 attempts 已达 maxAttempts → 置 dead(lastError 含 visibility),不无限重跑;
|
|
72
|
+
* - `enqueue` 幂等键冲突返回已有任务(created=false),不报错;
|
|
73
|
+
* - `payload` 必须 JSON 可序列化。
|
|
74
|
+
*/
|
|
75
|
+
export interface TaskStore {
|
|
76
|
+
enqueue(input: EnqueueInput): Promise<StoreEnqueueResult>;
|
|
77
|
+
claim(options: ClaimOptions): Promise<Task[]>;
|
|
78
|
+
complete(id: string, now: Date): Promise<void>;
|
|
79
|
+
fail(id: string, input: FailInput, now: Date): Promise<void>;
|
|
80
|
+
/** 归还任务(关闭超时/未知 handler):running → pending,attempts 保留 */
|
|
81
|
+
release(id: string, runAt: Date, now: Date): Promise<void>;
|
|
82
|
+
/** 死信手动重驱:dead → pending,attempts 归零 */
|
|
83
|
+
retry(id: string, now: Date): Promise<boolean>;
|
|
84
|
+
get(id: string): Promise<Task | null>;
|
|
85
|
+
list(filter?: ListFilter): Promise<Task[]>;
|
|
86
|
+
/** 清理终态任务(默认 done/dead),按 updatedAt 早于 now-olderThanMs */
|
|
87
|
+
prune(options: PruneOptions): Promise<number>;
|
|
88
|
+
/** 到期待执行的 distinct name(未知 handler 告警用) */
|
|
89
|
+
pendingNames(now: Date): Promise<string[]>;
|
|
90
|
+
migrate?(): Promise<void>;
|
|
91
|
+
}
|
|
92
|
+
export interface TaskContext {
|
|
93
|
+
id: string;
|
|
94
|
+
name: string;
|
|
95
|
+
/** 本次是第几次尝试(从 1 开始) */
|
|
96
|
+
attempt: number;
|
|
97
|
+
}
|
|
98
|
+
export type TaskHandler = (payload: any, ctx: TaskContext) => void | Promise<void>;
|
|
99
|
+
export interface TaskLogger {
|
|
100
|
+
warn(message: string): void;
|
|
101
|
+
error(message: string): void;
|
|
102
|
+
}
|
|
103
|
+
/** `tasks.install(app)` 只需要 onClose 能力 */
|
|
104
|
+
export interface CloseableApp {
|
|
105
|
+
onClose(disposer: () => void | Promise<void>): unknown;
|
|
106
|
+
}
|
|
107
|
+
export interface CreateTasksOptions {
|
|
108
|
+
store: TaskStore;
|
|
109
|
+
/** 单进程并发执行数,默认 1 */
|
|
110
|
+
concurrency?: number;
|
|
111
|
+
/** 轮询间隔,默认 1000ms */
|
|
112
|
+
pollIntervalMs?: number;
|
|
113
|
+
/** 单任务运行超过该时长只告警不中断,默认 30s */
|
|
114
|
+
warnAfterMs?: number;
|
|
115
|
+
/** 可见性超时(崩溃恢复),默认 60s */
|
|
116
|
+
visibilityTimeoutMs?: number;
|
|
117
|
+
/** 指数退避:默认 base 1s / max 15min */
|
|
118
|
+
retry?: {
|
|
119
|
+
baseMs?: number;
|
|
120
|
+
maxMs?: number;
|
|
121
|
+
};
|
|
122
|
+
now?: () => Date;
|
|
123
|
+
workerId?: string;
|
|
124
|
+
logger?: TaskLogger;
|
|
125
|
+
/** 进程内 worker 默认开启;测试可关 */
|
|
126
|
+
autoStart?: boolean;
|
|
127
|
+
}
|
|
128
|
+
export interface EnqueueOptions {
|
|
129
|
+
delay?: number;
|
|
130
|
+
runAt?: Date;
|
|
131
|
+
idempotencyKey?: string;
|
|
132
|
+
maxAttempts?: number;
|
|
133
|
+
}
|
|
134
|
+
export interface Tasks {
|
|
135
|
+
readonly store: TaskStore;
|
|
136
|
+
handle(name: string, handler: TaskHandler): Tasks;
|
|
137
|
+
enqueue(name: string, payload?: unknown, options?: EnqueueOptions): Promise<EnqueueResult>;
|
|
138
|
+
/** 周期任务:首次立即到期,完成后排下一次(宕机后 catch-up) */
|
|
139
|
+
every(name: string, intervalMs: number, payload?: unknown): Tasks;
|
|
140
|
+
/** 接入应用生命周期:启动 worker + `app.close()` 时优雅停止(默认 5s) */
|
|
141
|
+
install(app: CloseableApp, options?: {
|
|
142
|
+
timeoutMs?: number;
|
|
143
|
+
}): Tasks;
|
|
144
|
+
start(): void;
|
|
145
|
+
stop(options?: {
|
|
146
|
+
timeoutMs?: number;
|
|
147
|
+
}): Promise<void>;
|
|
148
|
+
/** 取一批(≤ concurrency)到期任务执行一次,返回执行数 */
|
|
149
|
+
runOnce(): Promise<number>;
|
|
150
|
+
/** 反复 runOnce 直到无到期任务(测试/内嵌调度) */
|
|
151
|
+
drain(options?: {
|
|
152
|
+
maxIterations?: number;
|
|
153
|
+
}): Promise<void>;
|
|
154
|
+
retry(id: string): Promise<boolean>;
|
|
155
|
+
list(filter?: ListFilter): Promise<Task[]>;
|
|
156
|
+
readonly running: boolean;
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,iCAAiC"}
|