export function startScheduleReminderWorker({ scheduleService, sendWechatTextToUser, logger = console, intervalMs = Number(process.env.H5_REMINDER_SCAN_INTERVAL_MS ?? 30_000), maxAttempts = Number(process.env.H5_REMINDER_MAX_ATTEMPTS ?? 5), runOnStart = true, } = {}) { if (!scheduleService || typeof sendWechatTextToUser !== 'function') { return { stop() {} }; } let stopped = false; let running = false; const runOnce = async () => { if (running || stopped) return; running = true; try { const due = await scheduleService.listDueDigestSubscriptions({ limit: 50 }); for (const candidate of due) { const subscription = await scheduleService.lockDigestSubscription(candidate.id); if (!subscription) continue; try { const text = await scheduleService.buildTodoDigestText({ userId: subscription.userId, timezone: subscription.timezone, }); await sendWechatTextToUser(subscription.userId, text); await scheduleService.logDelivery({ subscriptionId: subscription.id, userId: subscription.userId, channel: subscription.channel, status: 'success', }); await scheduleService.markDigestSent(subscription); } catch (err) { logger.warn?.('Schedule digest delivery failed:', err); await scheduleService.logDelivery({ subscriptionId: subscription.id, userId: subscription.userId, channel: subscription.channel, status: 'failed', errorMessage: err instanceof Error ? err.message : String(err), }).catch(() => {}); await scheduleService.markDigestFailed(subscription, err, { maxAttempts }); } } } catch (err) { logger.warn?.('Schedule reminder worker failed:', err); } finally { running = false; } }; const timer = setInterval(runOnce, Math.max(1000, Number(intervalMs) || 30_000)); timer.unref?.(); if (runOnStart) void runOnce(); return { runOnce, stop() { stopped = true; clearInterval(timer); }, }; }