Skip to content

fix(dashboard): keep session DB reads off event loop - #53966

Closed
0-CYBERDYNE-SYSTEMS-0 wants to merge 1 commit into
NousResearch:mainfrom
0-CYBERDYNE-SYSTEMS-0:codex/dashboard-session-db-off-event-loop
Closed

0-CYBERDYNE-SYSTEMS-0 wants to merge 1 commit into
NousResearch:mainfrom
0-CYBERDYNE-SYSTEMS-0:codex/dashboard-session-db-off-event-loop

Conversation

@0-CYBERDYNE-SYSTEMS-0

Copy link
Copy Markdown

Summary

Fix a dashboard event-loop starvation path caused by session database reads during desktop startup.

  • Move /api/status active-session counting into a worker thread with asyncio.to_thread(...).
  • Convert /api/sessions and /api/profiles/sessions to sync FastAPI handlers so their blocking SessionDB work runs in FastAPI's worker pool.
  • Add a regression test that makes SessionDB.list_sessions_rich(...) slow and proves another API request can respond before that slow DB read finishes.

Root cause

The desktop can see the backend port listening and the dashboard ready signal while later API calls still silently time out. One uncovered cause is synchronous SessionDB work running inside async FastAPI handlers, starving the event loop during status/session reads. In the reproduced failure, a slow SessionDB.list_sessions_rich(...) delayed an unrelated API request until the DB read completed.

Relation to existing PRs

This complements, but does not duplicate:

This PR keeps the scope to session/status DB reads and their regression coverage.

Verification

python -m pytest tests/hermes_cli/test_web_server_boot_handshake.py -q -o 'addopts='
python -m py_compile hermes_cli/web_server.py tests/hermes_cli/test_web_server_boot_handshake.py
git diff --check origin/main...HEAD

Results: focused pytest passed (4 passed), py_compile passed, and diff check passed.

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review Summary

Verdict: Approved

Clean refactoring: moves blocking SQLite SessionDB queries off the async event loop using asyncio.to_thread. The extraction of _count_active_sessions() as a sync helper is the right pattern. The two sync get_sessions / get_profiles_sessions route handlers correctly dropped the async keyword since they do synchronous DB work. Test confirms the event loop is not blocked (version endpoint completes within timeout).


Reviewed by Hermes Agent

@alt-glitch alt-glitch added type/perf Performance improvement or optimization comp/dashboard Web dashboard / control panel UI (dashboard/, landing) comp/cli CLI entry point, hermes_cli/, setup wizard P3 Low — cosmetic, nice to have sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state labels Jun 28, 2026
@alt-glitch

Copy link
Copy Markdown
Contributor

This was generated by AI during triage.

Related: #50948 (moves other dashboard sync I/O off the event loop), #45491 (offloads cron profile scans), and the umbrella RFC #48564 (dashboard/TUI event-loop-starvation hardening). This PR is scoped specifically to session/status DB reads, so it complements rather than duplicates those — the cluster as a whole is chipping away at the same desktop-startup event-loop-starvation class.

liuhao1024 pushed a commit to liuhao1024/hermes-agent that referenced this pull request Jul 8, 2026
Flip the handler from async def to sync def so FastAPI executes it in
its threadpool: the SessionDB open + list_sessions_rich query no longer
block the single uvicorn event loop.

Residual hunk from PR NousResearch#53966 — that PR's get_profiles_sessions flip
already landed via NousResearch#54523/1bb7b59c5, and its get_status offload is
superseded by NousResearch#58238's read_only + timeout variant in this branch.

(cherry picked from commit 414c12a)
@kshitijk4poor

Copy link
Copy Markdown
Contributor

Merged via #60884 (rebase) — the residual hunk of this PR (the GET /api/sessions sync-def flip) landed on main as 24d5bda under your authorship. Your other two hunks were already covered: get_profiles_sessions landed earlier via #54523/1bb7b59c5, and the get_status offload was superseded by #58238's read-only + timeout variant (merged in the same batch). Thanks!

santhreal pushed a commit to santhreal/hermes-agent that referenced this pull request Jul 13, 2026
Flip the handler from async def to sync def so FastAPI executes it in
its threadpool: the SessionDB open + list_sessions_rich query no longer
block the single uvicorn event loop.

Residual hunk from PR NousResearch#53966 — that PR's get_profiles_sessions flip
already landed via NousResearch#54523/6f78e9cd2, and its get_status offload is
superseded by NousResearch#58238's read_only + timeout variant in this branch.

(cherry picked from commit 414c12a)
justemu pushed a commit to justemu/hermes-agent that referenced this pull request Jul 18, 2026
Flip the handler from async def to sync def so FastAPI executes it in
its threadpool: the SessionDB open + list_sessions_rich query no longer
block the single uvicorn event loop.

Residual hunk from PR NousResearch#53966 — that PR's get_profiles_sessions flip
already landed via NousResearch#54523/1bb7b59c5, and its get_status offload is
superseded by NousResearch#58238's read_only + timeout variant in this branch.

(cherry picked from commit 414c12a)
Gravezzz pushed a commit to Gravezzz/hermes-agent that referenced this pull request Jul 21, 2026
Flip the handler from async def to sync def so FastAPI executes it in
its threadpool: the SessionDB open + list_sessions_rich query no longer
block the single uvicorn event loop.

Residual hunk from PR NousResearch#53966 — that PR's get_profiles_sessions flip
already landed via NousResearch#54523/1bb7b59c5, and its get_status offload is
superseded by NousResearch#58238's read_only + timeout variant in this branch.

(cherry picked from commit 414c12a)
leewenjie pushed a commit to leewenjie/hermes-agent that referenced this pull request Aug 7, 2026
Flip the handler from async def to sync def so FastAPI executes it in
its threadpool: the SessionDB open + list_sessions_rich query no longer
block the single uvicorn event loop.

Residual hunk from PR NousResearch#53966 — that PR's get_profiles_sessions flip
already landed via NousResearch#54523/1bb7b59c5, and its get_status offload is
superseded by NousResearch#58238's read_only + timeout variant in this branch.

(cherry picked from commit 414c12a)
randlee pushed a commit to randlee/hermes-agent that referenced this pull request Aug 11, 2026
Flip the handler from async def to sync def so FastAPI executes it in
its threadpool: the SessionDB open + list_sessions_rich query no longer
block the single uvicorn event loop.

Residual hunk from PR NousResearch#53966 — that PR's get_profiles_sessions flip
already landed via NousResearch#54523/2229a295a, and its get_status offload is
superseded by NousResearch#58238's read_only + timeout variant in this branch.

(cherry picked from commit 414c12a)
melon-xf added a commit to melon-xf/hermes-agent that referenced this pull request Sep 3, 2026
Flip the handler from async def to sync def so FastAPI executes it in
its threadpool: the SessionDB open + list_sessions_rich query no longer
block the single uvicorn event loop.

Residual hunk from PR NousResearch#53966 — that PR's get_profiles_sessions flip
already landed via NousResearch#54523/1bb7b59c5, and its get_status offload is
superseded by NousResearch#58238's read_only + timeout variant in this branch.

(cherry picked from commit 414c12a)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard comp/dashboard Web dashboard / control panel UI (dashboard/, landing) P3 Low — cosmetic, nice to have sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/perf Performance improvement or optimization

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants