fix(httpserver): guard OnStop against nil srv when OnStart was never called
If a component earlier in the launcher sequence fails during OnInit or OnStart,
the launcher calls OnStop on every already-registered component for cleanup.
httpserver.OnStop previously called s.srv.Shutdown(ctx) unconditionally; because
s.srv is only assigned inside OnStart, any shutdown triggered before OnStart ran
caused a nil pointer panic.
Add an early return in OnStop: `if s.srv == nil { return nil }`.
This commit is contained in:
@@ -5,6 +5,14 @@ All notable changes to this module will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this module adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.9.1] - 2026-03-21
|
||||
|
||||
### Fixed
|
||||
|
||||
- `OnStop` now returns `nil` immediately when `s.srv == nil`, preventing a nil pointer
|
||||
panic when the launcher calls cleanup on a server component whose `OnStart` was never
|
||||
reached (e.g. because an earlier component failed during startup).
|
||||
|
||||
## [0.9.0] - 2026-03-18
|
||||
|
||||
### Added
|
||||
@@ -25,4 +33,5 @@ and this module adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.
|
||||
- No middleware is installed by default; the full middleware stack is composed explicitly via `WithMiddleware` at construction time, keeping the stack visible and ordering unambiguous in the application source
|
||||
- chi was chosen as the underlying router because it uses stdlib `http.Handler` throughout, making it fully compatible with `httpmw` middleware and `httputil` handler adapters without any wrapper code at the boundary
|
||||
|
||||
[0.9.1]: https://code.nochebuena.dev/go/httpserver/releases/tag/v0.9.1
|
||||
[0.9.0]: https://code.nochebuena.dev/go/httpserver/releases/tag/v0.9.0
|
||||
|
||||
@@ -107,8 +107,12 @@ func (s *httpServer) OnStart() error {
|
||||
}
|
||||
|
||||
// OnStop performs a graceful shutdown, waiting up to 10 seconds for in-flight
|
||||
// requests to complete.
|
||||
// requests to complete. If OnStart was never called (e.g. a prior component
|
||||
// failed during startup), this is a no-op.
|
||||
func (s *httpServer) OnStop() error {
|
||||
if s.srv == nil {
|
||||
return nil
|
||||
}
|
||||
s.logger.Info("httpserver: shutting down gracefully")
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
Reference in New Issue
Block a user