Skip to content

fix(session): end SQLite sessions when suspending to prevent zombie sessions (#9090)#10171

Open
easyvibecoding wants to merge 1 commit into
NousResearch:mainfrom
easyvibecoding:fix/session-end-on-suspend
Open

fix(session): end SQLite sessions when suspending to prevent zombie sessions (#9090)#10171
easyvibecoding wants to merge 1 commit into
NousResearch:mainfrom
easyvibecoding:fix/session-end-on-suspend

Conversation

@easyvibecoding

Copy link
Copy Markdown

Summary

SessionStore.suspend_session() and suspend_recently_active() only set suspended=True in sessions.json but never wrote ended_at to SQLite. When a session is later auto-reset on next access, get_or_create_session() calls end_session() with reason 'session_reset', BUT only if the entry is still in _entries. If the gateway crashed and the session was NOT re-loaded from disk (e.g. Feishu WebSocket sessions not yet persisted), the zombie session remains in SQLite with ended_at=NULL forever.

Fix: both suspend_session() and suspend_recently_active() now also call self._db.end_session(session_id, 'suspended') when the DB is available, ensuring ended_at is always populated when a session is suspended. When the session is later accessed and auto-reset, the UPDATE re-runs with end_reason='session_reset', which is the correct final state.

Closes #9090.

Changes

  • gateway/session.py: suspend_session() — now also calls self._db.end_session() to populate SQLite ended_at
  • gateway/session.py: suspend_recently_active() — same, iterates all suspended sessions and ends each in SQLite

Test plan

python -m pytest -o addopts='' tests/gateway/test_session.py -q
python -m py_compile gateway/session.py

…essions (NousResearch#9090)

Root cause: suspend_session() and suspend_recently_active() only set
suspended=True in sessions.json but never wrote ended_at to SQLite.
When the suspended session was later auto-reset on next access,
get_or_create_session() would call end_session() with reason
'session_reset', BUT only if the entry was still in _entries.
If the gateway crashed and the session was NOT re-loaded from disk
on restart (e.g. Feishu WebSocket sessions not yet persisted),
the zombie session remained in SQLite with ended_at=NULL.

Fix: both suspend_session() and suspend_recently_active() now also
call self._db.end_session(session_id, 'suspended') when the DB is
available, ensuring ended_at is always populated when a session is
suspended. When the session is later accessed and auto-reset, the
UPDATE re-runs with end_reason='session_reset', which is the correct
final state.

Also changes return value of suspend_session() from bool to True
iff an entry existed (for clearer caller feedback).
@easyvibecoding easyvibecoding force-pushed the fix/session-end-on-suspend branch from 02f0dad to aca751a Compare April 15, 2026 08:28
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/gateway Gateway runner, session dispatch, delivery labels Apr 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Feishu WebSocket sessions not closed on gateway restart — zombie sessions accumulate in DB

2 participants