perf: remote browser CPU / zombie optimization

- Add tini (init: true in compose) to reap orphan Chromium processes
- Reduce screenshot push frequency (active 0.12→0.20s, idle 0.35→1.00s,
  deep idle 1.00→5.00s, backoff 0.60→2.00s)
- Add 5s timeout to screenshot in WebSocket push loop
- close() now wraps context.close() in asyncio.wait_for(10s)
  with browser.close() fallback on timeout
- Two-phase close logging (closing → closed / close_failed)
- Auth-capture sessions evicted after 10min TTL
- shutdown() with timeout protection and logging
- close_ok correctly tracks success through browser fallback path
This commit is contained in:
liumangmang
2026-06-01 15:47:08 +08:00
parent c8ba25f08e
commit a949969c4d
4 changed files with 75 additions and 19 deletions
+12 -7
View File
@@ -265,12 +265,12 @@ async def clear_profile(custom_page_id: int, _=Depends(get_current_user)):
# ——— WebSocket stream ———
# Frame interval & diff detection
_WS_MIN_INTERVAL = 0.10
_WS_IDLE_INTERVAL = 0.35
_WS_ACTIVE_INTERVAL = 0.12
_WS_BACKOFF_INTERVAL = 0.60
_WS_DEEP_IDLE_INTERVAL = 1.00
# Frame interval & diff detection (tuned for CPU efficiency)
_WS_MIN_INTERVAL = 0.15
_WS_IDLE_INTERVAL = 1.00
_WS_ACTIVE_INTERVAL = 0.20
_WS_BACKOFF_INTERVAL = 2.00
_WS_DEEP_IDLE_INTERVAL = 5.00
_WS_ACTIVE_WINDOW = 1.25
@@ -361,7 +361,12 @@ async def session_ws(
state = await browser_sessions.state(session_id)
await websocket.send_json({"type": "state", "session": state})
frame = await browser_sessions.screenshot(session_id)
frame = await asyncio.wait_for(
browser_sessions.screenshot(session_id), timeout=5.0)
except asyncio.TimeoutError:
logger.warning("ws screenshot timeout for %s", session_id[:12])
await asyncio.sleep(interval)
continue
except KeyError:
await websocket.send_json({"error": "session_not_found"})
break