Documentation
¶
Overview ¶
Package shutdown provides a small primitive for gracefully shutting down an application: register named hooks, wait for an OS signal, then run the hooks in FILO (last-registered, first-run) order under a shared grace period, with optional Before constraints that adjust ordering.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrEmptyHookName is returned when a hook is registered without a name. ErrEmptyHookName = errors.New("hook name must not be empty") // ErrNilShutdownFunc is returned when a hook is registered without a // shutdown function. ErrNilShutdownFunc = errors.New("hook shutdown function must not be nil") // ErrDuplicateHookName is returned when a hook is registered with a // name that is already in use. Each name must be unique within a // Shutdown instance. ErrDuplicateHookName = errors.New("hook with this name is already registered") )
Sentinel errors returned by Add when a hook is rejected.
Functions ¶
This section is empty.
Types ¶
type Hook ¶
type Hook struct {
Name string
ShutdownFn func(ctx context.Context) error
// contains filtered or unexported fields
}
Hook is a shutdown hook that will be called when signal is received.
type HookOption ¶
type HookOption func(*Hook)
HookOption configures a Hook at registration time.
func Before ¶
func Before(before string) HookOption
Before declares that the hook should run before the named hook during Listen. Because Listen iterates the registered slice in reverse (FILO), "run before X" means "ordered after X in the slice". If the named target is empty, equal to the hook's own name, or unknown at registration time, Before is a no-op.
type Option ¶
type Option func(*Shutdown)
Option is the options type to configure Shutdown.
func WithGracePeriodDuration ¶
WithGracePeriodDuration sets the grace period for all shutdown hooks to finish running. If not used, the default grace period is 30s.
func WithHooks ¶
WithHooks adds the hooks to be run as part of the graceful shutdown. Any hook that fails validation in Add (empty name, nil shutdown function, duplicate name) is logged at warning level and skipped; the remaining hooks are still registered.
Note: Hook.before is unexported, so external callers using WithHooks cannot express a Before constraint. To use Before, register hooks via Add directly.
type Shutdown ¶
type Shutdown struct {
// contains filtered or unexported fields
}
Shutdown provides a way to listen for signals and handle shutdown of an application gracefully.
Example ¶
package main
import (
"context"
"errors"
"fmt"
"log"
"log/slog"
"net/http"
"syscall"
"time"
"github.com/triple-a/gocom/shutdown"
)
func main() {
textHandler := slog.DiscardHandler
logger := slog.New(textHandler)
shutdownHandler := shutdown.New(
logger,
shutdown.WithHooks(
[]shutdown.Hook{
{
Name: "do something",
ShutdownFn: func(_ context.Context) error {
return nil
},
},
},
),
shutdown.WithGracePeriodDuration(time.Second))
var srv http.Server
go func() {
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Fatalf("http server listen and serve: %s", err)
}
}()
shutdownHandler.Add("http server", func(ctx context.Context) error {
if err := srv.Shutdown(ctx); err != nil {
return fmt.Errorf("http server shutdown: %w", err)
}
return nil
})
if err := shutdownHandler.Listen(
context.Background(),
syscall.SIGHUP,
syscall.SIGINT,
syscall.SIGTERM,
syscall.SIGQUIT); err != nil {
log.Fatalf("graceful shutdown failed: %s. forcing exit.", err)
}
}
Output:
func New ¶
New returns a new Shutdown with the provided options. If logger is nil, slog.Default() is used.
func (*Shutdown) Add ¶
func (s *Shutdown) Add( name string, shutdownFunc func(ctx context.Context) error, hookOpts ...HookOption, ) error
Add registers a shutdown hook. Returns ErrEmptyHookName if name is empty, ErrNilShutdownFunc if shutdownFunc is nil, or ErrDuplicateHookName if a hook with this name is already registered.
func (*Shutdown) Hooks ¶
Hooks returns the registered shutdown hooks ordered for execution. Hooks without a Before constraint keep registration order; Before constraints are applied so that each constrained hook is positioned to run before its named target during Listen's reverse iteration. If a circular dependency is detected, the unresolved hooks are appended at the end and a warning is logged.
func (*Shutdown) Listen ¶
Listen waits for the signals provided and executes each shutdown hook sequentially in FILO order. It will immediately stop and return once the grace period has passed.
Hooks must honor the ctx passed to them and return promptly when it is cancelled; a hook that ignores ctx will leave its goroutine running after Listen returns when the grace period is exceeded.