feat(M01-C): 建立MySQL异步任务基础
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { OutboxRepository } from '../dist/tasks/outbox-repository.js';
|
||||
import { retryDelayMs, taskTypes } from '../dist/tasks/task-repository.js';
|
||||
import { TaskWorker } from '../dist/tasks/worker.js';
|
||||
|
||||
assert.deepEqual(taskTypes, [
|
||||
'notification.dispatch',
|
||||
'order.advance',
|
||||
'device.command',
|
||||
'refund.query',
|
||||
'statistics.aggregate',
|
||||
'outbox.publish'
|
||||
]);
|
||||
assert.equal(retryDelayMs(1), 1000);
|
||||
assert.equal(retryDelayMs(4), 8000);
|
||||
assert.equal(retryDelayMs(99), 60 * 60 * 1000);
|
||||
|
||||
const outboxCalls = [];
|
||||
const outbox = new OutboxRepository({
|
||||
async execute(sql, params) {
|
||||
outboxCalls.push([sql, params]);
|
||||
return [{ insertId: 7, affectedRows: 1 }, []];
|
||||
}
|
||||
});
|
||||
assert.deepEqual(
|
||||
await outbox.append({
|
||||
tenantId: '1',
|
||||
aggregateType: 'order',
|
||||
aggregateId: '88',
|
||||
eventType: 'order.paid',
|
||||
idempotencyKey: 'order:88:paid',
|
||||
payload: { orderId: '88' }
|
||||
}),
|
||||
{ id: '7', created: true }
|
||||
);
|
||||
assert.match(outboxCalls[0][0], /INSERT IGNORE INTO qipai_outbox_events/);
|
||||
|
||||
const calls = [];
|
||||
const task = {
|
||||
id: '42',
|
||||
tenantId: '1',
|
||||
taskType: 'notification.dispatch',
|
||||
idempotencyKey: 'notice:42',
|
||||
payload: { channel: 'test' },
|
||||
status: 'RUNNING',
|
||||
attempts: 1,
|
||||
maxAttempts: 3
|
||||
};
|
||||
const repository = {
|
||||
async claimNext() {
|
||||
calls.push('claim');
|
||||
return task;
|
||||
},
|
||||
async complete(id) {
|
||||
calls.push(`complete:${id}`);
|
||||
return true;
|
||||
},
|
||||
async fail() {
|
||||
calls.push('fail');
|
||||
}
|
||||
};
|
||||
const worker = new TaskWorker({
|
||||
repository,
|
||||
handlers: new Map([['notification.dispatch', async (claimed) => {
|
||||
calls.push(`handle:${claimed.id}`);
|
||||
}]]),
|
||||
workerId: 'test-worker'
|
||||
});
|
||||
assert.equal(await worker.runOnce(), true);
|
||||
assert.deepEqual(calls, ['claim', 'handle:42', 'complete:42']);
|
||||
|
||||
const failedCalls = [];
|
||||
const failedWorker = new TaskWorker({
|
||||
repository: {
|
||||
async claimNext() { return task; },
|
||||
async complete() { return true; },
|
||||
async fail(claimed, workerId, error) {
|
||||
failedCalls.push([claimed.id, workerId, error.message]);
|
||||
}
|
||||
},
|
||||
handlers: new Map(),
|
||||
workerId: 'test-worker'
|
||||
});
|
||||
assert.equal(await failedWorker.runOnce(), true);
|
||||
assert.deepEqual(failedCalls, [['42', 'test-worker', 'No handler registered for task type notification.dispatch.']]);
|
||||
|
||||
console.log('PASS: M01-C task retry and worker contracts are present.');
|
||||
Reference in New Issue
Block a user