feat(shutdown): add graceful shutdown #530

Merged
fuzzy merged 1 commit from feat/graceful-shutdown into main 2026-08-04 20:18:56 +00:00
Owner

What

Add a coordinated graceful shutdown on SIGINT/SIGTERM:

  • Cleanup funcbuildRouter now returns a func() that closes the auth middleware, releasing keyfunc's JWKS refresh goroutine (fixes #524).
  • Readiness flip/readyz is backed by a caller-provided flag (Deps.Ready); on shutdown the daemon flips it not-ready before draining, so ingress/k8s stop routing new traffic while /healthz stays green.
  • Server hardeningReadHeaderTimeout/ReadTimeout/WriteTimeout/IdleTimeout on the http.Server so the drain cannot hang on slow or leaky clients.
  • Goroutine join — the preview GC goroutine is tracked with a WaitGroup and joined after shutdown so the process waits for it to observe cancellation before exiting.
  • README documents the shutdown behavior.

Why

Phase 9 task #120 — production readiness: predictable, ordered shutdown that drains in-flight work and releases background resources.

Testing

  • go build ./...
  • go vet ./...
  • go test -race -count=1 ./... — full suite passes
  • New tests: readiness flip (/readyz 503 while /healthz stays 200) and runPreviewGC returning promptly on context cancellation and on invalid config
  • gofmt -l ./cmd ./internal ./pkg clean
  • golangci-lint run — 0 issues
  • pre-commit hooks all pass

Breaking Changes

None.

Notes

  • Issues #120 and #524 closed via the Forgejo API as part of this task per the workflow.
  • The ratelimit cleanup goroutine wiring is deferred to PR #526 (its package isn't on main yet); its StartCleanup will stop via the signal context.

Closes #120
Closes #524

## What Add a coordinated graceful shutdown on `SIGINT`/`SIGTERM`: - **Cleanup func** — `buildRouter` now returns a `func()` that closes the auth middleware, releasing keyfunc's JWKS refresh goroutine (**fixes #524**). - **Readiness flip** — `/readyz` is backed by a caller-provided flag (`Deps.Ready`); on shutdown the daemon flips it not-ready before draining, so ingress/k8s stop routing new traffic while `/healthz` stays green. - **Server hardening** — `ReadHeaderTimeout`/`ReadTimeout`/`WriteTimeout`/`IdleTimeout` on the `http.Server` so the drain cannot hang on slow or leaky clients. - **Goroutine join** — the preview GC goroutine is tracked with a `WaitGroup` and joined after shutdown so the process waits for it to observe cancellation before exiting. - README documents the shutdown behavior. ## Why Phase 9 task #120 — production readiness: predictable, ordered shutdown that drains in-flight work and releases background resources. ## Testing - [x] `go build ./...` - [x] `go vet ./...` - [x] `go test -race -count=1 ./...` — full suite passes - [x] New tests: readiness flip (`/readyz` 503 while `/healthz` stays 200) and `runPreviewGC` returning promptly on context cancellation and on invalid config - [x] `gofmt -l ./cmd ./internal ./pkg` clean - [x] `golangci-lint run` — 0 issues - [x] pre-commit hooks all pass ## Breaking Changes None. ## Notes - Issues #120 and #524 closed via the Forgejo API as part of this task per the workflow. - The ratelimit cleanup goroutine wiring is deferred to PR #526 (its package isn't on main yet); its `StartCleanup` will stop via the signal context. Closes #120 Closes #524
feat(shutdown): add graceful shutdown
All checks were successful
Test and Release / lint (pull_request) Successful in 7m2s
Test and Release / test (pull_request) Successful in 7m15s
3bb95d50da
Coordinate a clean shutdown on SIGINT/SIGTERM:

- buildRouter now returns a cleanup func that closes the auth middleware,
  releasing the keyfunc JWKS refresher goroutine (#524)
- /readyz is backed by a caller-provided flag so the daemon flips
  not-ready before draining, letting ingress/k8s stop routing new traffic
  during shutdown
- http.Server gains ReadHeaderTimeout/ReadTimeout/WriteTimeout/IdleTimeout
  so the drain cannot hang on slow or leaky clients
- the preview GC goroutine is joined via a WaitGroup so shutdown waits for
  it to observe cancellation before exiting
- README documents the shutdown behavior

Tests cover the readiness flip (readyz 503 while healthz stays 200) and
runPreviewGC returning promptly on context cancellation and on invalid
config.

closes #120
closes #524
fuzzy force-pushed feat/graceful-shutdown from 3bb95d50da
All checks were successful
Test and Release / lint (pull_request) Successful in 7m2s
Test and Release / test (pull_request) Successful in 7m15s
to 2b117e7e4c
All checks were successful
Test and Release / test (pull_request) Successful in 2m47s
Test and Release / lint (pull_request) Successful in 5m52s
2026-08-04 20:18:05 +00:00
Compare
fuzzy merged commit 2b117e7e4c into main 2026-08-04 20:18:56 +00:00
fuzzy deleted branch feat/graceful-shutdown 2026-08-04 20:18:56 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
thwap/thwap-pagesd!530
No description provided.