mirror of
https://github.com/hansjone/netx.git
synced 2026-10-13 06:13:16 +08:00
Expose worker scheduler health via heartbeat and isolate WebCRT IO.
API /metrics and /health/ready now read a worker heartbeat when collectors are split out; WebCRT blocking I/O uses a dedicated executor so session pumps do not starve the default pool. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
7b62824c2c
commit
f64835749a
12 changed files with 366 additions and 13 deletions
|
|
@ -17,6 +17,7 @@ from .auth_deps import AuthContext, require_user, resolve_user_from_token
|
|||
from .auth_scopes import SCOPE_WEBCRT, has_scope
|
||||
from .config import settings
|
||||
from .webcrt_tickets import consume_ws_ticket, issue_ws_ticket
|
||||
from .webcrt_io import webcrt_io_executor
|
||||
from .webcrt_service import (
|
||||
close_session,
|
||||
create_session,
|
||||
|
|
@ -450,7 +451,7 @@ async def websocket_session(websocket: WebSocket, session_id: str) -> None:
|
|||
slice_timeout = min(1.0, max(0.2, remaining))
|
||||
try:
|
||||
await loop.run_in_executor(
|
||||
None,
|
||||
webcrt_io_executor(),
|
||||
lambda t=slice_timeout: wait_session_ready(session_id, timeout=t),
|
||||
)
|
||||
sess = get_session(session_id) or cur
|
||||
|
|
@ -533,7 +534,7 @@ async def websocket_session(websocket: WebSocket, session_id: str) -> None:
|
|||
data = "".join(stdin_buf)
|
||||
stdin_buf = []
|
||||
try:
|
||||
await asyncio.get_running_loop().run_in_executor(None, sess.write_stdin, data)
|
||||
await asyncio.get_running_loop().run_in_executor(webcrt_io_executor(), sess.write_stdin, data)
|
||||
except Exception as exc:
|
||||
await websocket.send_json(
|
||||
{"type": "status", "state": "error", "message": f"write_failed:{exc}"}
|
||||
|
|
@ -589,7 +590,7 @@ async def websocket_session(websocket: WebSocket, session_id: str) -> None:
|
|||
while not stop.is_set():
|
||||
# Longer block is cheap now (Condition wait); cuts executor churn when idle.
|
||||
chunk = await loop.run_in_executor(
|
||||
None, lambda: sess.take_stdout(attach_gen, timeout=0.2)
|
||||
webcrt_io_executor(), lambda: sess.take_stdout(attach_gen, timeout=0.2)
|
||||
)
|
||||
if chunk == "stale":
|
||||
break
|
||||
|
|
@ -626,7 +627,7 @@ async def websocket_session(websocket: WebSocket, session_id: str) -> None:
|
|||
if sess.needs_live_prompt:
|
||||
sess.needs_live_prompt = False
|
||||
try:
|
||||
await asyncio.get_running_loop().run_in_executor(None, sess.write_stdin, "\r")
|
||||
await asyncio.get_running_loop().run_in_executor(webcrt_io_executor(), sess.write_stdin, "\r")
|
||||
except Exception:
|
||||
_log.debug("webcrt live prompt sync failed session=%s", session_id, exc_info=True)
|
||||
try:
|
||||
|
|
@ -667,10 +668,10 @@ async def websocket_session(websocket: WebSocket, session_id: str) -> None:
|
|||
elif mtype == "resize":
|
||||
cols = int(msg.get("cols") or sess.cols)
|
||||
rows = int(msg.get("rows") or sess.rows)
|
||||
await asyncio.get_running_loop().run_in_executor(None, sess.resize, cols, rows)
|
||||
await asyncio.get_running_loop().run_in_executor(webcrt_io_executor(), sess.resize, cols, rows)
|
||||
elif mtype == "break":
|
||||
try:
|
||||
await asyncio.get_running_loop().run_in_executor(None, sess.send_break)
|
||||
await asyncio.get_running_loop().run_in_executor(webcrt_io_executor(), sess.send_break)
|
||||
except Exception as exc:
|
||||
await websocket.send_json(
|
||||
{"type": "status", "state": "error", "message": f"break_failed:{exc}"}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue