Visitar URL original
fix: deliver reminders persisted as queued/running instead of losing them on restart by MatrixNeoKozak · Pull Request #83 · QwenAudio/qwen-audio-agent · GitHub
Skip to content

fix: deliver reminders persisted as queued/running instead of losing them on restart - #83

Merged
x-lixu merged 3 commits into
QwenAudio:mainfrom
MatrixNeoKozak:fix/fix-deliver-reminders-persisted-as-queued-running-instead-of-losing-them-on-restart-1785932017917
Aug 10, 2026
Merged

x-lixu merged 3 commits into
QwenAudio:mainfrom
MatrixNeoKozak:fix/fix-deliver-reminders-persisted-as-queued-running-instead-of-losing-them-on-restart-1785932017917

Conversation

@MatrixNeoKozak

Copy link
Copy Markdown
Contributor

What

Fixes a real reminder-loss bug in the scheduled-task lifecycle (issue #80's core invariant: reminders are "never silently lost").

ReminderScheduler.fire() and restoreOverdue() transition a reminder from scheduled -> queued and persist that state before drain() starts it (persistDeferred is called immediately; the restore-overdue stagger window can keep a reminder in persisted 'queued' state for minutes). If the Gateway restarts in that window, TaskManager.restore() treats the saved 'queued'/'running' entry as an ordinary active task and hard-fails it with "qwen-audio-agent 重启时这项工作尚未完成" — the reminder content is never spoken.

Fix: in restore(), entries of kind 'reminder' persisted in an ACTIVE status are restored as 'scheduled' (with the passthrough speech runner rebuilt), so ReminderScheduler.start()'s restoreOverdue() path staggers and fires them as overdue catch-up, exactly like reminders that expired while the Gateway was down. This is safe for reminders because their runner only speaks the stored text — unlike scheduled_task entries, whose backend work may have partially run and therefore intentionally still fail on restart.

Added a unit test covering the restart-catch-up path: a reminder persisted in 'queued' state with a past due time is restored as 'scheduled' with a function runner and no error.

Scope note: this addresses the restart-durability edge of the existing schedule_reminder implementation rather than adding the new frontend store from the issue's design; the bug fix keeps the current reminder pipeline intact.

Why

This change resolves the target issue or improvement.

How to test

Verify that the project builds/runs correctly and the specific bug/improvement is addressed.

Fixes #80

@ngoanpv ngoanpv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The at-least-once choice looks right for queued/running — a duplicated spoken reminder after a crash is clearly better than a silently lost one, and the passthrough runner makes re-firing safe.

One edge worth a look: ACTIVE also contains 'cancelling'. A reminder persisted mid-cancellation (user said cancel, Gateway stopped before the transition completed) would be restored as 'scheduled' by this patch and then fire as overdue catch-up — resurrecting a reminder the user explicitly cancelled. Excluding 'cancelling' from the restartAsScheduled condition (letting it fall through to the existing restart-failure path, or restoring it as cancelled) would keep the fix while preserving cancellation intent. Might be worth a companion test case with status: 'cancelling'.

@x-lixu x-lixu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已复核并优化:Gateway 重启后仅恢复 queued/running 的持久化提醒,避免 cancelling 提醒被复活;补充了对应回归测试。完整 release check 与跨平台 CI 均通过。

@x-lixu
x-lixu merged commit 365eb29 into QwenAudio:main Aug 10, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: frontend reminders/timers (roadmap P2, T1-T5) - implementation plan and claim

3 participants