mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-15 14:22:43 +00:00
fix(dashboard): keep session DB reads off event loop
This commit is contained in:
parent
88b3d8638e
commit
414c12a40d
2 changed files with 63 additions and 14 deletions
|
|
@ -1910,6 +1910,22 @@ async def fs_default_cwd():
|
|||
return {"cwd": cwd, "branch": _fs_git_branch(cwd)}
|
||||
|
||||
|
||||
def _count_active_sessions() -> int:
|
||||
from hermes_state import SessionDB
|
||||
|
||||
db = SessionDB()
|
||||
try:
|
||||
sessions = db.list_sessions_rich(limit=50)
|
||||
now = time.time()
|
||||
return sum(
|
||||
1 for s in sessions
|
||||
if s.get("ended_at") is None
|
||||
and (now - s.get("last_active", s.get("started_at", 0))) < 300
|
||||
)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
@app.get("/api/status")
|
||||
async def get_status(profile: Optional[str] = None):
|
||||
status_scope = None
|
||||
|
|
@ -2008,18 +2024,7 @@ async def get_status(profile: Optional[str] = None):
|
|||
|
||||
active_sessions = 0
|
||||
try:
|
||||
from hermes_state import SessionDB
|
||||
db = SessionDB()
|
||||
try:
|
||||
sessions = db.list_sessions_rich(limit=50)
|
||||
now = time.time()
|
||||
active_sessions = sum(
|
||||
1 for s in sessions
|
||||
if s.get("ended_at") is None
|
||||
and (now - s.get("last_active", s.get("started_at", 0))) < 300
|
||||
)
|
||||
finally:
|
||||
db.close()
|
||||
active_sessions = await asyncio.to_thread(_count_active_sessions)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
|
@ -3137,7 +3142,7 @@ async def get_action_status(name: str, lines: int = 200):
|
|||
|
||||
|
||||
@app.get("/api/sessions")
|
||||
async def get_sessions(
|
||||
def get_sessions(
|
||||
limit: int = 20,
|
||||
offset: int = 0,
|
||||
min_messages: int = 0,
|
||||
|
|
@ -3226,7 +3231,7 @@ async def get_sessions(
|
|||
|
||||
|
||||
@app.get("/api/profiles/sessions")
|
||||
async def get_profiles_sessions(
|
||||
def get_profiles_sessions(
|
||||
limit: int = 20,
|
||||
offset: int = 0,
|
||||
min_messages: int = 0,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ from unittest.mock import patch
|
|||
import pytest
|
||||
|
||||
import hermes_cli.web_server as web_server_mod
|
||||
import hermes_state
|
||||
|
||||
SLOW_SECONDS = 3 # represents the Defender worst-case (scaled down for CI speed)
|
||||
|
||||
|
|
@ -186,3 +187,46 @@ def test_concurrent_status_probes_all_respond():
|
|||
f"{len(failed)}/{PROBES} probes failed (codes: {responses}). "
|
||||
f"This would cause WinError 10054 and orphan accumulation on desktop."
|
||||
)
|
||||
|
||||
|
||||
def test_status_session_count_does_not_block_event_loop(monkeypatch):
|
||||
import httpx
|
||||
|
||||
class SlowSessionDB:
|
||||
def list_sessions_rich(self, limit: int = 50):
|
||||
time.sleep(SLOW_SECONDS)
|
||||
return []
|
||||
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
monkeypatch.setattr(hermes_state, "SessionDB", SlowSessionDB)
|
||||
results: dict[str, float | int] = {}
|
||||
|
||||
async def _run():
|
||||
transport = httpx.ASGITransport(app=web_server_mod.app)
|
||||
async with httpx.AsyncClient(transport=transport, base_url="http://test") as client:
|
||||
scenario_started = time.perf_counter()
|
||||
async with asyncio.TaskGroup() as tg:
|
||||
async def _status():
|
||||
t = time.perf_counter()
|
||||
r = await client.get("/api/status", timeout=SLOW_SECONDS + 5)
|
||||
results["status_ms"] = (time.perf_counter() - t) * 1000
|
||||
results["status_code"] = r.status_code
|
||||
|
||||
async def _version():
|
||||
await asyncio.sleep(0.1)
|
||||
t = time.perf_counter()
|
||||
r = await client.get("/api/version", timeout=5)
|
||||
results["version_ms"] = (time.perf_counter() - t) * 1000
|
||||
results["version_elapsed_ms"] = (time.perf_counter() - scenario_started) * 1000
|
||||
results["version_code"] = r.status_code
|
||||
|
||||
tg.create_task(_status())
|
||||
tg.create_task(_version())
|
||||
|
||||
asyncio.run(_run())
|
||||
|
||||
assert results.get("version_code") in {200, 401}
|
||||
assert results.get("status_code") == 200
|
||||
assert results["version_elapsed_ms"] < SLOW_SECONDS * 1000
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue