feat(deploy): SSE deployments — live progress, health check, and history/detail#1399
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces Server-Sent Events (SSE) streaming support for live component deployment progress and adds a deployment history view for Harper >= 5.1.0. Feedback focuses on resolving a connection leak in the SSE stream parser, a memory leak in the manual anySignal fallback, a potential runtime crash on unexpected error payloads, and a performance bottleneck in log rendering caused by shifting array index keys.
kriszyp
left a comment
There was a problem hiding this comment.
Approving — awesome work, @dawsontoth! 🎉 The SSE deployment flow is carefully built: clean connection lifecycle, no double-deploy, well-defined progress/health/history state, and the event log is bounded at 1000 so it can't grow unbounded. Two minor UI nits in the thread, neither blocking.
— 🤖 KrAIs (Kris's review assistant)
|
@kriszyp or KrAIs, can you expand upon your " Two minor UI nits in the thread, neither blocking." comment? I don't see a thread! 😅 |
|
We want to land #1400 before this PR since it will unlock the SSE when someone is using fabric connect, improving the experience a lot. |
d35ae54 to
62ba45d
Compare
…ory/detail Adopt Harper 5.1.0's SSE deploy stream and `hdb_deployment` audit table (harper#641). All gated on Harper >= 5.1.0; 5.0.x keeps today's buffered path. Closes #1233, #1231, #1230. ## Reusable browser SSE transport (src/integrations/api/sse/) - resolveInstanceConnection: fetch-equivalent of getInstanceClient's auth/URL resolution (axios is XHR and can't stream response bodies); getInstanceClient left untouched. - parseSSEStream: robust SSE record parser (chunk-split, CRLF, multi-line data, comments). - streamOperation: fetch+stream with three explicit outcomes — SSEUnsupportedError (fall back to buffered), SSEOperationError (failed), and SSEInconclusiveError (poll, never assume success); idle-timeout watchdog. ## Deploy (#1233) - deployComponentStream + deployComponent mutation: stream when supported, fall back to the buffered POST on SSEUnsupportedError only (never re-POST after a deploy has started — no double deploys). - DeployProgress + useDeploymentStream: live phase checklist, install-log tail, peer results, wired into the redeploy modal and import flow. - Post-deploy health check (useComponentHealthCheck): polls get_components for the new per-component status, since deploy_component now returns before worker threads finish loading. ## Deployments history + detail (#1230, #1231) - list_deployments / get_deployment (JSON read + SSE tail) + hdb_deployment types. - New Config sub-nav "Deployments": a table (project/status/started/completed/ user/origin) with a row -> detail modal showing metadata, peer_results, and the event_log activity timeline. Deep-linked from the cluster card. - Detail uses active-polling as the correctness backbone, with the SSE tail layered on for live granularity. ## Proxy note The central-manager fabric-connect proxy buffers text/event-stream (verified live), so live SSE is gated to direct connections; proxied entities use the buffered deploy + polling detail, which work fully. Drop the checkForFabricConnect check in useSupportsDeploymentSSE if the proxy gains streaming passthrough. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The modal passed `overflow-y-auto`/`max-h` to the resizable DialogContent, but the resizable shell deliberately leaves its outer content unclipped so the resize handles (which extend past the edges at negative insets) stay reachable. Clipping there swallowed the handles — draggable but not resizable. Move scrolling onto an inner `flex-1 min-h-0 overflow-y-auto` body, matching ViewLogModal/EditTableRowModal. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The mount effect set `unmountedRef.current = true` in its cleanup but never reset it on setup. Under React StrictMode's dev mount→cleanup→remount the cleanup fires once and the ref persists, leaving the flag stuck `true` — so every gesture teardown skipped its `setIsDragging(false)` / `setIsResizing(false)`, and the overlay stayed transparent after releasing a drag. Reset the flag on (re)mount. Affects all resizable dialogs; production (no StrictMode double-invoke) was already fine, but this makes the teardown guard robust either way. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…able log keys - parseSSEStream: cancel the reader when a consumer breaks early (or aborts) so the underlying connection is released instead of left open (browser per-host cap). - streamOperation: anySignal now returns a cleanup that detaches listeners from the caller's signal (manual fallback path), invoked in a single outer finally; guard the terminal `error` payload against null/primitive before reading its fields. - useDeploymentStream/DeployProgress: give each install-log line a stable id and key on it, so front-slicing the capped log doesn't churn every row's React key. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
62ba45d to
a1b6b7a
Compare
…able Leverage the direct-connect (Bearer operation token) path so SSE actually streams instead of buffering through the central-manager proxy, and keep the deployments table fresh without manual refresh. - resolveInstanceConnection: mirror getInstanceClient's direct-connect precedence — prefer the direct instance URL + Bearer operation token (and Basic), only using the proxy URL when genuinely proxy-only. Expose mode: 'direct' | 'proxy'. - authStore.isDirectConnection(id): true when operations go straight to the instance (Bearer token, or no Fabric Connect) — i.e. when SSE can stream. - useSupportsDeploymentSSE: gate on isDirectConnection, not merely the absence of the Fabric Connect flag, so Fabric-Connect-resolved-to-direct clusters get live SSE. - list_deployments: pollWhileOpen option — refetch while the Deployments view is open (2s while a deploy is active, 10s otherwise). hdb_deployment is a system table and isn't exposed as a subscribable resource, so polling is the live-update mechanism. - New Application import toast streams live phase + install-output lines when SSE is available (richer progress), falling back to the plain toast otherwise. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
What & why
Adopts Harper 5.1.0's SSE deploy stream and the replicated
hdb_deploymentaudit table (harper#641) in Studio. Everything is gated on Harper ≥ 5.1.0 (verified against release tags: theSSE_PROGRESS_OPERATIONSbranch ships inv5.1.0and is absent inv5.0.31); 5.0.x keeps today's buffered deploy path unchanged.Closes #1233 · Closes #1231 · Closes #1230
Reusable browser SSE transport —
src/integrations/api/sse/The axios client is XHR-based and can't stream response bodies, and
EventSourceis GET-only (deploy is a POST), so SSE is consumed viafetch()+ a stream reader.resolveInstanceConnection— fetch-equivalent ofgetInstanceClient's base-URL/auth resolution (basic-auth header vscredentials: 'include'for the fabric-connect proxy).getInstanceClientitself is left untouched so its interceptors keep serving every non-streaming caller.parseSSEStream— SSE record parser (chunk-split, CRLF, multi-linedata:,:comments).streamOperation— three explicit outcomes:SSEUnsupportedError(fall back to buffered),SSEOperationError(failed),SSEInconclusiveError(poll — never assume success); idle-timeout watchdog.Deploy — #1233
deployComponentStream+ thedeployComponentmutation stream when supported, and fall back to the buffered POST only onSSEUnsupportedError(never re-POST after a deploy has started → no double deploys).DeployProgress+useDeploymentStream: live phase checklist, install-log tail, peer results — wired into the redeploy modal and import flow.useComponentHealthCheck): pollsget_componentsfor the new per-componentstatus, sincedeploy_componentnow returns before worker threads finish loading the component.Deployments history + detail — #1230 / #1231
list_deployments/get_deployment(JSON read and SSE tail) +hdb_deploymenttypes.peer_results, and theevent_logactivity timeline. Deep-linked from the cluster card's options menu.Verified live against a 5.1.14 cluster: a redeploy with
Accept: text/event-streamthrough the central-manager proxy sat 170s+ with zero response bytes whileget_components/list_deploymentsreturned instantly — the proxy bufferstext/event-stream. So live SSE is gated to direct connections; proxied (fabric-connect) entities use the buffered deploy + polling detail, which work fully. Drop thecheckForFabricConnectcheck inuseSupportsDeploymentSSEif/when the proxy gains streaming passthrough.Verification
hdb_deployment, appeared in the list, and the detail modal rendered full metadata + peer result + the event-log timeline; cluster-card deep-link navigates correctly; nav/version gating confirmed.🤖 Generated with Claude Code