graceful
Run a long-lived function with signal handling, context cancellation, optional timeouts, and
standardized exit codes. Independent of the cli package; useful for servers,
workers, and batch jobs.
import "github.com/pressly/cli/graceful"
At a glance
Each symbol links to its godoc entry, the canonical reference.
FUNCTIONS
func Run(run func(context.Context) error, opts ...Option)
func ListenAndServe(srv *http.Server, shutdownGrace time.Duration) func(context.Context) error
OPTIONS
func WithRunTimeout(d time.Duration) Option
func WithTerminationTimeout(d time.Duration) Option
func WithImmediateTermination() Option
func WithLogger(l *slog.Logger) Option
func WithStderr(w io.Writer) Option
Behavior
The first SIGINT or SIGTERM cancels the context passed into the run function, giving it a chance to shut down cleanly. A second signal forces an immediate exit. Optional timeouts bound the run duration and the total shutdown period.
Exit codes:
0: successful completion1: run function returned an error124: shutdown timeout exceeded130: forced shutdown (second signal or immediate termination)
Examples
HTTP server
First Ctrl+C drains in-flight requests for up to 15s. Second Ctrl+C forces an exit (130). Total time is capped at 30s (124 if exceeded).
server := &http.Server{
Addr: ":8080",
Handler: mux,
}
graceful.Run(
graceful.ListenAndServe(server, 15*time.Second),
graceful.WithTerminationTimeout(30*time.Second),
)
Batch job with a hard deadline
graceful.Run(
func(ctx context.Context) error {
return processBatch(ctx)
},
graceful.WithRunTimeout(1*time.Hour),
)
Immediate termination on first signal
graceful.Run(
func(ctx context.Context) error {
return runTask(ctx)
},
graceful.WithImmediateTermination(),
)
Silence shutdown messages
graceful.Run(fn,
graceful.WithLogger(slog.New(slog.DiscardHandler)),
)