| 1 | package console |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "log" |
| 6 | "time" |
| 7 | |
| 8 | "github.com/carlosframework/platform/internal/release" |
| 9 | ) |
| 10 | |
| 11 | // bumpSerial announces "the bucket has news" (carlos-deploy spec §3) after a |
| 12 | // write a box loop consumes. Log-only on failure and clamped to 2s: a lost |
| 13 | // bump costs latency (the hourly floor still converges), and no user-facing |
| 14 | // write may fail or stall because its announcement did. |
| 15 | // |
| 16 | // Every call site sits strictly AFTER the handler's own successful write, next |
| 17 | // to its audit row — never before a gate, and never in place of one. The |
| 18 | // serial carries no authority at all (it is the one unsigned object in the |
| 19 | // bucket); the worst a spurious bump can do is make a box run its ordinary |
| 20 | // signature-verified pass set a little early. |
| 21 | // |
| 22 | // context.WithoutCancel is the whole point of the ctx handling here: the |
| 23 | // caller's context is the REQUEST's, and by the time a bump runs the write it |
| 24 | // announces has already landed and is irreversible. A client that hangs up in |
| 25 | // that window (a CI runner killed mid-promote, a closed laptop, a proxy |
| 26 | // timeout) would otherwise cancel the announcement for a change that is |
| 27 | // permanently in the bucket — the fleet then waits out the hourly floor for a |
| 28 | // deploy that already happened, with nothing in any log to say why. The 2s |
| 29 | // clamp still applies, measured from here: detached from cancellation, not |
| 30 | // from time. |
| 31 | func (s *Server) bumpSerial(ctx context.Context) { |
| 32 | if s.cfg.Releases == nil { |
| 33 | return // no bucket on this console: nothing to announce into |
| 34 | } |
| 35 | ctx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 2*time.Second) |
| 36 | defer cancel() |
| 37 | if err := release.BumpSerial(ctx, s.cfg.Releases, time.Now()); err != nil { |
| 38 | log.Printf("console: serial bump: %v (boxes fall back to the hourly pass)", err) |
| 39 | } |
| 40 | } |
| 41 | |