Skip to content

feat(gateway): add crash checkpoint for precise session recovery - #8143

Open
chinadbo wants to merge 3 commits into
NousResearch:mainfrom
chinadbo:feat/session-state-recovery-on-crash
Open

feat(gateway): add crash checkpoint for precise session recovery#8143
chinadbo wants to merge 3 commits into
NousResearch:mainfrom
chinadbo:feat/session-state-recovery-on-crash

Conversation

@chinadbo

Copy link
Copy Markdown
Contributor

Summary

  • Added SessionCrashCheckpoint class that persists in-flight agent runs to agent_checkpoints.json
  • On agent start, the session key and ID are recorded; on clean completion, the entry is removed
  • On gateway restart, the checkpoint is read to precisely identify interrupted sessions, which are then suspended
  • The existing suspend_recently_active() time-window heuristic remains as fallback for sessions not tracked by the checkpoint
  • Checkpoint is cleared after processing so it doesn't accumulate stale entries

Test plan

  • 11 tests in tests/gateway/test_session_crash_recovery.py
  • Checkpoint write/read cycle for running and completed sessions
  • Edge cases: nonexistent file, corrupted JSON, mark_completed on unknown key, clear
  • Integration: crash simulation detects interrupted sessions, clean shutdown leaves empty checkpoint

@849497911-max

Copy link
Copy Markdown

This would solve session crash issues, please merge!

@chinadbo
chinadbo force-pushed the feat/session-state-recovery-on-crash branch from 9aa85f3 to 63d5af7 Compare April 27, 2026 07:03
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/gateway Gateway runner, session dispatch, delivery labels Apr 27, 2026
Persist in-flight agent runs to agent_checkpoints.json so that on
restart the gateway can precisely identify interrupted sessions instead
of relying solely on the suspend_recently_active time-window heuristic.
Sessions found in the checkpoint are suspended and the checkpoint is
cleared; the time-window heuristic remains as fallback.
- Fix startup ImportError: replace non-existent HERMES_HOME import with
  module-level _hermes_home variable (gateway was failing to start)
- Gate mark_completed on generation ownership: stale runs no longer
  clear the checkpoint entry when a newer generation owns the slot
- Add fsync + unique mkstemp to _write: checkpoint is now durable
  across power failures and safe under concurrent gateway instances
- Add defensive mark_completed on /stop sentinel fast-path for
  future-proofing if mark_running timing ever shifts
- Clear checkpoint on clean shutdown to prevent stale entries accumulating
- Add mark_completed after stale-eviction and interrupt-clear paths
- Move tempfile import to module level

@teknium1 teknium1 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.

Thanks for pursuing a real crash-recovery gap: current main still uses the 120-second updated_at sweep in gateway/session.py:2053-2087.

Problems

  • The checkpoint does not make recovery precise yet. gateway/run.py:2261-2269 reads and processes checkpoint entries, but gateway/run.py:2273-2275 immediately runs suspend_recently_active() for every recently updated session, retaining the false positives the checkpoint is intended to avoid.
  • The PR calls suspend_session() at gateway/run.py:2264. On current main, that is the hard auto-reset path (gateway/session.py:1932-1945); interruption continuity instead uses mark_resume_pending() (gateway/session.py:1947-1974) to preserve the transcript and session ID.
  • tests/gateway/test_session_crash_recovery.py:104-120 tests the checkpoint class alone, not gateway startup or the fallback interaction.

Suggested changes

  • Treat a valid checkpoint as authoritative and use the timestamp sweep only when no checkpoint is available.
  • Adapt recovery to current resume_pending semantics and add a runner-level test covering a checkpointed in-flight session plus a recently completed session.

Automated hermes-sweeper review.

Comment thread gateway/run.py

# Fallback: time-window heuristic for sessions not tracked by checkpoint.
try:
suspended = self.session_store.suspend_recently_active()

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.

This fallback still sweeps every recently updated session even when a checkpoint was present, so it reintroduces the false positives the checkpoint is meant to eliminate. Use the heuristic only when no valid checkpoint is available, or explicitly exclude the authoritative checkpoint recovery path.

Comment thread gateway/run.py
interrupted = self._crash_checkpoint.get_active_sessions()
if interrupted:
for session_key in interrupted:
self.session_store.suspend_session(session_key)

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.

On current main, suspend_session() is the hard auto-reset path. Crash continuity now uses mark_resume_pending() so the existing session ID and transcript survive; salvage should target that contract rather than reset the recovered session.

@teknium1 teknium1 added sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 12, 2026
@teknium1 teknium1 added the area/sessions Session lifecycle, resume, persistence, history label Jul 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/sessions Session lifecycle, resume, persistence, history comp/gateway Gateway runner, session dispatch, delivery P3 Low — cosmetic, nice to have sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants