Source File
httpprocess.go
Belonging Package
go.pact.im/x/httpprocess
// Package httpprocess provides [process.Runner] wrapper for [http.Server].
package httpprocess
import (
)
// Server returns a [process.Runner] instance for the given HTTP server and
// network listener.
func ( *http.Server, net.Listener) process.Runner {
var httptrack.ConnTracker
:= httptrack.Wrap(, &)
:= &nilCloserListener{Listener: }
return process.Leaf(
func( context.Context) error {
:= .BaseContext
.BaseContext = func( net.Listener) context.Context {
return
}
:= .Serve()
if errors.Is(, http.ErrServerClosed) {
= nil
}
if == nil {
= .CloseError()
}
// Wait until all connections are actually closed (i.e. until all
// per-connection goroutines return).
//
// Otherwise, process.Leaf would cancel the context on return, and
// the cancellation would propagate to in-flight HTTP handlers. We
// avoid that because our graceful shutdown model assumes the
// context only expires during forced shutdown.
//
// Note that this can still happen if the shutdown function returns,
// but by that point, graceful shutdown would have already failed.
.Wait()
.BaseContext =
.ConnState =
return
},
func( context.Context) error {
// Shutdown and Close forward error from net.Listener.Close.
// We already capture this error via nilCloserListener.
_ = .Shutdown()
_ = .Close()
return nil
},
)
}
// nilCloserListener is a wrapper around a [net.Listener] that ensures the
// underlying listener is closed exactly once and returns nil error.
type nilCloserListener struct {
net.Listener
once sync.Once
err error
}
// Close closes the underlying [net.Listener] exactly once. It always returns
// nil error.
func ( *nilCloserListener) () error {
.once.Do(func() { .err = .Listener.Close() })
return nil
}
// CloseError returns Close error from the underlying [net.Listener].
func ( *nilCloserListener) () error {
return .err
}
The pages are generated with Golds v0.7.6. (GOOS=linux GOARCH=amd64)