fix: add graceful shutdown to UI server#1747
Conversation
The UI server ignored the shutdown signal and had no way to stop: it used the package-level http.ListenAndServe, which offers no Shutdown. Build a dedicated http.Server on a local mux, watch the context, and drain requests within the grace period. The local mux also keeps routes registered by other packages off the UI port. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughSummary by CodeRabbit
WalkthroughChangesServeUI lifecycle
Estimated code review effort: 3 (Moderate) | ~20 minutes 🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
pkg/server/server.go (1)
107-110: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winAdd
ReadHeaderTimeoutto the UI HTTP server.The newly constructed
http.Serverhas no read, write, or idle timeouts, leaving it vulnerable to Slowloris-style resource exhaustion. Setting at leastReadHeaderTimeoutbounds how long the server waits for request headers. Consider addingWriteTimeoutandIdleTimeoutas well, bearing in mind that overly aggressive write timeouts can interrupt large SPA asset responses.🛡️ Proposed fix
server := &http.Server{ Addr: fmt.Sprintf(":%d", uiConfig.Port), Handler: mux, + ReadHeaderTimeout: 10 * time.Second, }Source: Linters/SAST tools
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 5d952878-b233-4d10-88a7-f499119869dc
📒 Files selected for processing (2)
pkg/server/serve_ui_test.gopkg/server/server.go
The dist folder is gitignored except for a placeholder, so in CI the embedded assets are empty and ServeUI exits before listening. Skip the shutdown test in that case, matching the condition ServeUI itself checks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Coverage Report for CI Build 29092121671Coverage decreased (-0.009%) to 44.867%Details
Uncovered Changes
Coverage Regressions5 previously-covered lines in 1 file lost coverage.
Coverage Stats
💛 - Coveralls |
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Summary
The UI server now shuts down gracefully on the process stop signal,
draining in-flight requests within the grace period.
Changes
ServeUIbuilds a dedicatedhttp.Serverinstead of calling thepackage-level
http.ListenAndServe, and shuts it down when thecontext is cancelled.
http.ServeMuxinstead of the globalDefaultServeMux, so the UI port serves only its own routes.elseblock (the branch above it returns).Technical Details
ListenAndServeruns in a goroutine reporting into a buffered channel;the main flow selects between server failure and context cancellation.
On cancellation it calls
Shutdownbounded by the existing graceperiod, so
ServeUIreturns only after in-flight requests finish. Astartup failure logs and returns, and the app keeps running since the
UI is optional.
Test Plan
TestServeUIReturnsAfterShutdownOnContextCancel(starts thereal server, polls
/configs, cancels, asserts clean return)TestServeUIReturnsWhenPortNotConfiguredgo test -race ./pkg/server/...passesgolangci-lint run pkg/server/reports 0 issues🤖 Generated with Claude Code