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:


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)),
)