From c2e9157822dc84a836ed1170b7507e99bc8f94d7 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Tue, 30 Jun 2026 19:38:37 -0400 Subject: [PATCH] feat(agent): graceful Start/Stop with starting/stopping states + instant status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Operator: the buttons fire but the status view doesn't reflect the change. Cause: act() ignored the POST's own status response and waited on the separate /status poll (which lags behind the curator queue call). Now: - act() applies the POST's returned status immediately for instant feedback, and shows an optimistic "starting"/"stopping" state (pulsing, buttons disabled) the moment it's clicked. - A stop that still has in-flight jobs draining shows "stopping" until active hits 0, then resolves to "stopped" on its own. - applyStatus() guards the /status-only fields (connection pill + queue) so the lean action response can't blank them — the Start/Stop path deliberately skips the slow curator call to stay snappy. Also de-duplicate GPU reads: read_gpu() now caches (1s TTL) with one probe at a time, and /status no longer spawns its own nvidia-smi — so the fast /gpu poll + autoscaler + /status share a single subprocess instead of piling up in the server thread pool (which was what made clicks feel dead under load). Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01Ttrj5P7upUTueSfoJcxEqa --- agent/fc_agent/app.py | 55 +++++++++++++++++++++++++++++++++---------- agent/fc_agent/gpu.py | 39 ++++++++++++++++++++++++++++-- 2 files changed, 79 insertions(+), 15 deletions(-) diff --git a/agent/fc_agent/app.py b/agent/fc_agent/app.py index b8a664f..1b4d0e3 100644 --- a/agent/fc_agent/app.py +++ b/agent/fc_agent/app.py @@ -77,7 +77,8 @@ def status(): s = worker.status() s["fc_url"] = cfg.fc_url s["configured"] = bool(cfg.token) - s["gpu"] = read_gpu() + # GPU is served by /gpu (cached); /status stays light so Start/Stop never + # queue behind it. try: s["queue"] = worker.client.queue_status() except Exception: @@ -116,6 +117,9 @@ _PAGE = """ .btn{font:600 14px system-ui;padding:.5rem 1rem;border:1px solid transparent;border-radius:9px; cursor:pointer;color:#fff;transition:.12s} .btn:hover{transform:translateY(-1px)} + .btn[disabled]{opacity:.45;pointer-events:none;transform:none} + @keyframes pulse{0%,100%{opacity:1}50%{opacity:.4}} + .tile .n.busy{color:var(--acc);animation:pulse 1s ease-in-out infinite} .btn.start{background:linear-gradient(180deg,#2f9c4c,#247a3c)} .btn.stop{background:linear-gradient(180deg,#3a3f48,#2a2f37);color:#e9edf2;border-color:var(--bd)} .switch{display:inline-flex;align-items:center;gap:8px;cursor:pointer;font-weight:600;user-select:none} @@ -171,8 +175,8 @@ _PAGE = """
Control
- - + +
@@ -211,7 +215,20 @@ _PAGE = """