feat(hub): Direction-2 immediate-sync wait channel (v0.58.0)
GET /api/v1/wait long-poll: the box holds an authed hanging GET; the hub completes it the instant any operator intent bumps that customer's in-memory generation, then the box fires its ordinary report and the ACK delivers everything through the unchanged machinery. 240s hold with a 25s heartbeat newline defeats the nginx 60s proxy_read_timeout with no ingress annotation; WriteTimeout lifted per-connection via ResponseController. - internal/intent: per-customer generation counter + waiter registry (Bump/Wait/Close), coalescing to latest, race-closer, in-memory by design. Red-proofs: counter-vs-queue + race-closer (run-fail-reverted). - api/wait.go: the endpoint (per-customer only; global key 400; A cannot see B). - web bumps after every intent write (fire-after-commit): config CRUD, claim resend, offsite re-issue/freeze, password regen, block/unblock, floors (global bumps all config-managed), controller log-tail + log-bundle. - main.go: one intent hub shared by web+api; Close() before server.Shutdown. Pairs with controller v0.140.0 (the long-poll client). Grounding: documentation/audits/SPIKE-immediate-sync-transport-2026-07-16.md.
This commit is contained in:
@@ -61,6 +61,12 @@ func (s *Server) handleRequestLogBundle(w http.ResponseWriter, r *http.Request,
|
||||
return
|
||||
}
|
||||
s.logger.Printf("[INFO] %s log bundle requested for host %s — the box delivers on its next cycle", component, hostID)
|
||||
// Direction-2: only the CONTROLLER ring rides the report ACK (the wait channel wakes the
|
||||
// controller). The AGENT ring rides the heartbeat envelope — a separate plane this task does not
|
||||
// touch — so it is deliberately NOT bumped here.
|
||||
if component == store.LogBundleComponentController {
|
||||
s.bumpIntent(host.CustomerID)
|
||||
}
|
||||
http.Redirect(w, r, "/hosts/"+hostID, http.StatusSeeOther)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user