shutdown

package module
v1.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 20, 2026 License: MIT Imports: 8 Imported by: 0

README

shutdown

import "github.com/triple-a/gocom/shutdown"

This package allows you to gracefully shutdown your app.

Index

type Hook

Hook is a shutdown hook that will be called when signal is received.

type Hook struct {
    Name       string
    ShutdownFn func(ctx context.Context) error
    // contains filtered or unexported fields
}

type HookOption

type HookOption func(*Hook)

func Before
func Before(before string) HookOption

type Option

Option is the options type to configure Shutdown.

type Option func(*Shutdown)

func WithGracePeriodDuration
func WithGracePeriodDuration(gracePeriodDuration time.Duration) Option

WithGracePeriodDuration sets the grace period for all shutdown hooks to finish running. If not used, the default grace period is 30s.

func WithHooks
func WithHooks(hooks []Hook) Option

WithHooks adds the hooks to be run as part of the graceful shutdown.

type Shutdown

Shutdown provides a way to listen for signals and handle shutdown of an application gracefully.

type Shutdown struct {
    // contains filtered or unexported fields
}
Example

package main

import (
	"context"
	"errors"
	"fmt"
	"io"
	"log"
	"log/slog"
	"net/http"
	"syscall"
	"time"

	"github.com/triple-a/gocom/shutdown"
)

func main() {
	textHandler := slog.NewTextHandler(io.Discard, nil)
	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)
	}
}

func New
func New(logger *slog.Logger, opts ...Option) *Shutdown

New returns a new Shutdown with the provided options.

func (*Shutdown) Add
func (s *Shutdown) Add(name string, shutdownFunc func(ctx context.Context) error, hookOpts ...HookOption)

Add adds a shutdown hook to be run when the signal is received.

func (*Shutdown) Hooks
func (s *Shutdown) Hooks() []Hook

Hooks returns a copy of the shutdown hooks, taking into account the before option

func (*Shutdown) Listen
func (s *Shutdown) Listen(ctx context.Context, signals ...os.Signal) error

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.

Generated by gomarkdoc

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

View Source
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

func WithGracePeriodDuration(gracePeriodDuration time.Duration) Option

WithGracePeriodDuration sets the grace period for all shutdown hooks to finish running. If not used, the default grace period is 30s.

func WithHooks

func WithHooks(hooks []Hook) Option

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

func New

func New(logger *slog.Logger, opts ...Option) *Shutdown

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

func (s *Shutdown) Hooks() []Hook

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

func (s *Shutdown) Listen(ctx context.Context, signals ...os.Signal) error

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL