fix(schedule): retry reminders when WeChat delivery is deferred
Memind CI / Test, build, and release guards (push) Successful in 3m32s

Treat deferred/skipped customer-service sends as failures so reminder worker
does not mark reminders sent, and add a 103 read-only health check script.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-09-16 21:30:53 +08:00
parent eecfb79042
commit d820247aa1
8 changed files with 485 additions and 6 deletions
+111
View File
@@ -289,3 +289,114 @@ test('scheduled task worker marks failure when page link is not deliverable yet'
assert.deepEqual(calls, ['failed:SCHEDULED_TASK_NON_DELIVERY', 'notify:scheduled_task_failed']);
});
test('scheduled task worker fails wechat-only task when delivery is deferred', async () => {
const calls = [];
const task = {
id: 'task-wechat-deferred',
userId: 'user-6',
title: '仅微信通知',
recurrence: 'once',
notifyChannel: 'wechat',
attempts: 1,
};
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) {
calls.push(`failed:${err.code}`);
return { ...input, status: 'failed', lastError: err.message };
},
},
notificationDispatcher: {
async sendScheduleNotification() {
return false;
},
},
executeTask: async () => ({
sessionId: 'session-6',
requestId: 'req-6',
deliveryText: '任务摘要已完成,详细内容已写入 MindSpace 工作区。',
readyPaths: [],
}),
logger: { warn() {} },
runOnStart: false,
});
await worker.runOnce();
worker.stop();
assert.deepEqual(calls, ['failed:WECHAT_SCHEDULE_NOTIFICATION_NOT_SENT']);
});
test('scheduled task worker keeps both-channel task when wechat is deferred but web succeeds', async () => {
const calls = [];
const task = {
id: 'task-both-deferred',
userId: 'user-7',
title: '双通道通知',
recurrence: 'once',
notifyChannel: 'both',
attempts: 1,
};
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(input, payload) {
calls.push(`success:${payload.result.wechatDelivery ? 'wechat' : 'web-only'}`);
return input;
},
async markTaskFailed() {
calls.push('failed');
},
},
scheduleService: {
async createUserNotification() {
calls.push('notify:web');
},
},
notificationDispatcher: {
async sendScheduleNotification() {
return false;
},
},
executeTask: async () => ({
sessionId: 'session-7',
requestId: 'req-7',
deliveryText: '任务摘要已完成,详细内容已写入 MindSpace 工作区。',
readyPaths: [],
}),
logger: { warn() {} },
runOnStart: false,
});
await worker.runOnce();
worker.stop();
assert.deepEqual(calls, ['notify:web', 'success:web-only']);
});