Add scheduled task automation skill with worker execution pipeline.
Memind CI / Test, build, and release guards (push) Failing after 18s
Memind CI / Test, build, and release guards (push) Failing after 18s
Introduce scheduled-task-automation for H5 and WeChat, persist tasks in h5_scheduled_tasks, and run due jobs via a dedicated worker that executes agent tasks and delivers results. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { startScheduledTaskWorker } from './scheduled-task-worker.mjs';
|
||||
|
||||
test('scheduled task worker executes due task and completes one-shot task', async () => {
|
||||
const calls = [];
|
||||
const notifications = [];
|
||||
const wechat = [];
|
||||
const task = {
|
||||
id: 'task-1',
|
||||
userId: 'user-1',
|
||||
title: '每日新闻页',
|
||||
taskSpec: '做新闻页',
|
||||
recurrence: 'once',
|
||||
notifyChannel: 'both',
|
||||
attempts: 1,
|
||||
};
|
||||
const worker = startScheduledTaskWorker({
|
||||
intervalMs: 60_000,
|
||||
userAuth: { id: 'user-auth' },
|
||||
tkmindProxy: { id: 'proxy' },
|
||||
scheduledTaskService: {
|
||||
async listDueTasks() {
|
||||
calls.push('list');
|
||||
return [task];
|
||||
},
|
||||
async lockTask(id) {
|
||||
calls.push(`lock:${id}`);
|
||||
return task;
|
||||
},
|
||||
async markTaskRunning(input) {
|
||||
calls.push(`running:${input.id}`);
|
||||
return { ...input, status: 'running' };
|
||||
},
|
||||
async markTaskSucceeded(input, payload) {
|
||||
calls.push(`success:${input.id}:${payload.deliveryText}`);
|
||||
return { ...input, status: 'completed' };
|
||||
},
|
||||
async markTaskFailed() {
|
||||
calls.push('failed');
|
||||
},
|
||||
},
|
||||
scheduleService: {
|
||||
async createUserNotification(input) {
|
||||
notifications.push(input.notificationType);
|
||||
},
|
||||
},
|
||||
notificationDispatcher: {
|
||||
async sendScheduleNotification({ userId, text }) {
|
||||
wechat.push({ userId, text });
|
||||
},
|
||||
},
|
||||
executeTask: async () => ({
|
||||
sessionId: 'session-1',
|
||||
requestId: 'req-1',
|
||||
deliveryText: '页面:https://example.com/news.html',
|
||||
}),
|
||||
logger: { warn() {}, info() {} },
|
||||
runOnStart: false,
|
||||
});
|
||||
|
||||
await worker.runOnce();
|
||||
worker.stop();
|
||||
|
||||
assert.deepEqual(calls, [
|
||||
'list',
|
||||
'lock:task-1',
|
||||
'running:task-1',
|
||||
'success:task-1:页面:https://example.com/news.html',
|
||||
]);
|
||||
assert.deepEqual(notifications, ['scheduled_task_result']);
|
||||
assert.equal(wechat.length, 1);
|
||||
assert.match(wechat[0].text, /定时任务完成:每日新闻页/);
|
||||
});
|
||||
|
||||
test('scheduled task worker marks failure after execution error', async () => {
|
||||
const calls = [];
|
||||
const task = {
|
||||
id: 'task-2',
|
||||
userId: 'user-2',
|
||||
title: '失败任务',
|
||||
recurrence: 'daily',
|
||||
notifyChannel: 'web',
|
||||
attempts: 3,
|
||||
};
|
||||
const worker = startScheduledTaskWorker({
|
||||
intervalMs: 60_000,
|
||||
userAuth: { id: 'user-auth' },
|
||||
tkmindProxy: { id: 'proxy' },
|
||||
scheduledTaskService: {
|
||||
async listDueTasks() {
|
||||
return [task];
|
||||
},
|
||||
async lockTask() {
|
||||
return task;
|
||||
},
|
||||
async markTaskRunning(input) {
|
||||
return input;
|
||||
},
|
||||
async markTaskSucceeded() {
|
||||
calls.push('success');
|
||||
},
|
||||
async markTaskFailed(input, err, { maxAttempts }) {
|
||||
calls.push(`failed:${maxAttempts}:${err.message}`);
|
||||
return { ...input, status: 'failed', lastError: err.message };
|
||||
},
|
||||
},
|
||||
scheduleService: {
|
||||
async createUserNotification(input) {
|
||||
calls.push(`notify:${input.notificationType}`);
|
||||
},
|
||||
},
|
||||
executeTask: async () => {
|
||||
throw new Error('agent timeout');
|
||||
},
|
||||
maxAttempts: 3,
|
||||
logger: { warn() {} },
|
||||
runOnStart: false,
|
||||
});
|
||||
|
||||
await worker.runOnce();
|
||||
worker.stop();
|
||||
|
||||
assert.deepEqual(calls, ['failed:3:agent timeout', 'notify:scheduled_task_failed']);
|
||||
});
|
||||
Reference in New Issue
Block a user