Skip to content

emrg: scheduler cycle heartbeat + next-run persistence (rant 2026-08-25T09:25:32) - #973

Merged
argszero merged 1 commit into
masterfrom
feature/scheduler-cycle-heartbeat-next-run
Aug 25, 2026
Merged

emrg: scheduler cycle heartbeat + next-run persistence (rant 2026-08-25T09:25:32)#973
argszero merged 1 commit into
masterfrom
feature/scheduler-cycle-heartbeat-next-run

Conversation

@pm25coder

Copy link
Copy Markdown
Collaborator

Implements stages ③④ of rant 2026-08-25T09:25:32 (daemon crash observability): TaskHandler cycle-progress heartbeat persistence + scheduler next-run persistence. Stages ①② (exit records + crash log) already merged via #970 (5080dad).

Changes

emrg/server/scheduler.py

  • _cycle_progress now records current stage, round, and a last-activity timestamp while a TaskHandler cycle is running; persisted as a heartbeat file (<task-runs-dir>/<name>.heartbeat.json) alongside the existing saturation state, written after each round update (write order fixed so the persisted round never lags the in-memory state)
  • Scheduler next-run time is persisted too, so a daemon restart no longer resets the schedule to "now" — after a crash you can identify "interrupted at round X of stage Y" from the heartbeat file

tests/test_scheduler.py (+3 tests)

  • heartbeat file written during cycle rounds with correct stage/round values
  • next-run + heartbeat persistence survives a simulated restart (mirrors the existing test_slowdown_state_persisted_across_restart)

Agent.md — doc-count guard synced (1058→1061 for the 3 new tests)

Verification

  • pytest full suite: 995 passed / 65 skipped
  • from emrg.client.app import run_client OK, python -m emrg --help OK
  • Agent.md doc-count guard re-run: 4 passed

Rant (verbatim)

daemon 异常退出无任何日志痕迹,死因无法定位(已 2 例可考:8-24 20:40 腰斩 R46、8-25 02:00 腰斩 emrg-task 01:26 轮并跳过 promote 06:06 调度)。emrgd.log 在死亡瞬间无 shutdown/错误/退出码记录,重启后一切正常。请求日志/可观测性增强(非防死):① daemon 退出无论正常/异常都写退出记录(退出码、信号、traceback);② stderr/stdout 独立重定向到崩溃日志文件;③ TaskHandler 运行中 cycle 定期持久化进度心跳,重启后能识别"上次中断于 round X";④ scheduler next run 持久化,重启不重置。目标:下次再出现时能定位原因。

@argszeroargszero left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

✅ LGTM — cycle (1/3)

Reviewed the full diff (3 files, +312/−1, scheduler cycle heartbeat + next-run persistence, rant 2026-08-25T09:25:32 items ③ and ④).

Design check (③ heartbeat): <task>.heartbeat.json written on every tool frame (round + tool_count mirrored from the daemon frames) + periodic 60s writer; removed in the run() finally path via _clear_heartbeat(); a daemon killed mid-cycle leaves status=running and the next TaskHandler init restores progress + logs interrupted at round X — makes the 8-24/8-25 silent-death incidents diagnosable from emrgd.log alone. heartbeat_task is created before the try block so the finally's cancel() is always safe. Best-effort writes (try/except pass) never affect the running cycle.

Design check (④ next-run): ~/.emrg/next-run/<task>.json persists the scheduled slot; _resume_wait_timeout folds it in one-shot — only ever shortens (min(wait_timeout, remaining)), an already-passed slot runs immediately (0.0), stale files ignored, cleared state deletes the file. Symmetric with the heartbeat: mid-cycle → heartbeat survives; mid-wait → next-run survives.

Verification (local, independent of CI): checked out the PR head — uv run pytest tests/test_scheduler.py tests/test_doc_counts.py -q96 passed including the 3 new tests (heartbeat tracking+clearing, interrupted-cycle reporting, next-run persistence across restart with one-shot/expired/stale/cleared sub-states — both positive and negative branches covered). Agent.md 1058→1061 matches the +3 test functions (doc-count guard green). CI double-green (run 32811638111: test + test-windows). No issues — solid observability/persistence PR.

@argszeroargszero left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

✅ LGTM — cycle (2/3)

Re-verified this cycle: head unchanged (9da76a78, same commit reviewed at 1/3), CI still double-green (run 32811638111: test + test-windows pass), mergeable CLEAN.

Re-confirmed the two design invariants on the same code:

  • ③ heartbeat: _heartbeat_loop created before the cycle try-block → finally always cancels safely; _write_heartbeat best-effort (never raises); interrupted-cycle detection reads status=running only.
  • ④ next-run: _resume_wait_timeout is one-shot (clears _resume_next_run_at), only shortens the wait, expired slot → 0.0 immediate run.

Local verification from the 1/3 review stands: 96 passed (scheduler + doc-count, incl. 3 new tests, both positive/negative branches). No issues — consistent with the first vote.

@argszeroargszero left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

✅ LGTM — cycle (3/3)

Third independent review of 9da76a78 (scheduler cycle heartbeat + next-run persistence, 3 files, +312/−1). Head unchanged since 2/3; CI double-green (run 32811638111: test + test-windows pass); mergeable CLEAN. No ❌ in the review history.

Both design invariants re-confirmed on the same code (③ heartbeat written per tool-frame + cleared on clean end, interrupted cycles reported on restart; ④ next-run persisted one-shot, only shortens, expired slot runs immediately). Local verification stands from the 1/3 review: 96 passed incl. 3 new tests with both positive/negative branches. Three consecutive LGTMs across cycles — merging.

@argszero
argszero merged commit 7160fb4 into masterAug 25, 2026
2 checks passed
Sign up for freeto 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.

2 participants

@pm25coder@argszero