HERMES-GIELIE/api
Isla-Liu 5b41f03a92 fix(webui): close sqlite3 connections in handoff-summary path (#2233)
Two functions on the /api/session/handoff-summary hot path were opening
sqlite3.connect(...) inside a bare `with` statement, which commits the
transaction at scope exit but does NOT close the connection. Per-turn
invocations accumulated state.db / state.db-wal file descriptors and
CPython heap pages on long-lived worker threads, surfacing as the
multi-GB VmRSS and 6x duplicated state.db fds observed on the live
instance (D0 pre-restart baseline: VmRSS 1,334,248 kB, 55 fds; cold
baseline after restart: VmRSS 136,668 kB, 10 fds).

Wrap both call sites with contextlib.closing(...) (already imported and
used at seven other sites in the same files) so the connection is
closed deterministically:

  - api/models.py :: count_conversation_rounds
  - api/routes.py :: _persist_handoff_summary_to_state_db

Regression test:
  tests/test_issue2233_sqlite_connection_leak.py loops both functions
  20 times against a tmp state.db and asserts /proc/<pid>/fd count
  does not grow more than 2. Linux-only via sys.platform skip.

D1 live soak against a freshly-built worktree server (port 8799,
isolated HERMES_HOME / HERMES_WEBUI_STATE_DIR) hitting
/api/session/handoff-summary 20 times:

  fd_before      = 5
  fd_after       = 5     (growth 0, threshold < 5)
  vmrss_before   = 52636 kB
  vmrss_after    = 52636 kB  (growth 0 kB, threshold < 30 MB)

The patched fix curve trends below the leak curve.

Rollback: single git revert <this-sha> reverts both file edits.

Refs #2233.
2026-05-22 18:34:06 +08:00
..
__init__.py
agent_health.py fix(agent-health): treat stale running gateway as unknown 2026-05-11 23:13:09 +00:00
agent_sessions.py fix: keep resumed CLI sessions in sidebar cap 2026-05-20 15:54:44 -07:00
auth.py Add session-bound CSRF token checks 2026-05-18 07:14:26 +08:00
background.py feat(commands): /background, /btw slash commands + undo button + reasoning chip 2026-04-24 01:24:51 +00:00
clarify.py chore: address review notes — dedup comment and 409-path clarification 2026-05-20 19:57:20 +00:00
commands.py fix(security): drop unsafe-eval + add jsdelivr to CSP, sanitize plugin error 2026-05-11 17:53:02 +00:00
compression_anchor.py feat(webui): render indexed context metadata 2026-05-19 18:52:50 +00:00
config.py Stage 398: PR #2700 — feat: make pinned session limit configurable (builds on shipped #2614 3-cap) 2026-05-21 17:43:56 +00:00
dashboard_probe.py fix: preserve IPv6 dashboard link brackets 2026-05-19 21:35:10 -04:00
extensions.py Opus pre-release follow-ups for PR #1445 2026-05-02 03:49:40 +00:00
gateway_watcher.py release: v0.50.241 (#1293) 2026-04-29 19:54:07 -07:00
goals.py fix(i18n): localize /goal runtime status strings 2026-05-10 15:21:24 +08:00
helpers.py stage-348: apply Opus SHOULD-FIX-pre-merge — add '://' to _SENSITIVE_LOWER_MARKERS 2026-05-13 16:54:36 +00:00
kanban_bridge.py stage-315 absorb: document handle_kanban_* three-valued return contract 2026-05-07 18:52:01 +00:00
metering.py fix: show TPS in assistant message headers 2026-05-04 21:26:43 +00:00
models.py fix(webui): close sqlite3 connections in handoff-summary path (#2233) 2026-05-22 18:34:06 +08:00
oauth.py fix(oauth): serialize Anthropic env fallback reads 2026-05-07 02:47:19 +00:00
onboarding.py Classify onboarding DNS probe failures consistently 2026-05-15 08:51:30 +08:00
profiles.py Stage 393: PR #2637 2026-05-20 22:24:40 +00:00
providers.py fix: show config-managed custom providers 2026-05-20 06:27:00 -07:00
request_diagnostics.py fix: add request wedge diagnostics 2026-05-08 15:37:08 +00:00
rollback.py v0.50.255: Opus follow-ups (4 fixes) + CHANGELOG 2026-05-01 17:19:53 +00:00
routes.py fix(webui): close sqlite3 connections in handoff-summary path (#2233) 2026-05-22 18:34:06 +08:00
run_journal.py Address run journal replay review 2026-05-16 02:58:34 +00:00
runtime_adapter.py Stage 398: PR #2696 — feat(runtime): add runner-local adapter selection (RuntimeAdapter slice 4c, feature-flagged) 2026-05-21 17:43:54 +00:00
session_events.py sync session list from server events 2026-05-20 08:18:56 -06:00
session_lifecycle.py fix: align WebUI memory commits with CLI boundaries 2026-05-17 05:04:57 -06:00
session_ops.py Show profile home in /status command (refs #463) (#1380) 2026-05-01 04:46:37 +00:00
session_recovery.py fix(session): rebuild missing startup index 2026-05-20 23:43:30 +08:00
startup.py fix: P0 hotfixes — API regression, code block parser, chmod override 2026-05-01 12:10:48 +00:00
state_sync.py
streaming.py Stage 399: PR #2704 — fix(streaming): prevent exponential empty _partial accumulation across reasoning-only cancellations 2026-05-21 17:56:46 +00:00
system_health.py feat: add VPS resource health panel 2026-05-05 17:30:56 +00:00
terminal.py fix: reap terminal shells on shutdown 2026-05-19 04:57:51 -07:00
turn_journal.py fix: lock turn journal appends 2026-05-15 16:39:45 -07:00
updates.py Stage 400: PR #2719 — fix: apply release update target (clear sessionStorage check-once stamp + force banner re-evaluation on user click) 2026-05-21 22:59:56 +00:00
upload.py fix(upload): scope archive extraction to per-session attachment dir 2026-05-18 21:22:02 +03:00
usage.py fix: display canonical cache hit percentage 2026-05-19 02:27:12 -06:00
workspace.py feat(workspace): add backend Git operations 2026-05-20 04:51:41 +00:00
workspace_git.py fix(workspace): tighten git subprocess trust boundary 2026-05-20 11:02:45 +00:00
worktrees.py Harden worktree removal safeguards 2026-05-13 09:49:15 +08:00