shutdown

package
v0.13.0 Latest Latest
Warning

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

Go to latest
Published: Feb 13, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// ExitOK indicates successful termination.
	//
	// Use when:
	//   - the application completed its work successfully
	//   - a server shut down gracefully after receiving SIGTERM
	//   - a CLI command or seed finished without errors
	//
	// MUST be used for normal, expected shutdown.
	ExitOK = 0

	// ExitGeneralError indicates an unspecified failure.
	//
	// Use when:
	//   - an error occurred but does not fit a more specific category
	//   - acting as a fallback error code
	//
	// Avoid using this when a more precise exit code exists.
	ExitGeneralError = 1

	// ExitUsage indicates incorrect command usage.
	//
	// Use when:
	//   - CLI arguments are invalid
	//   - required flags are missing
	//   - incompatible flags are provided
	//
	// Typical for CLI tools and admin commands.
	ExitUsage = 64

	// ExitDataError indicates invalid input data.
	//
	// Use when:
	//   - input data is malformed
	//   - JSON / YAML / CSV parsing fails due to invalid content
	//   - semantic validation fails
	ExitDataError = 65

	// ExitNoInput indicates a missing required input.
	//
	// Use when:
	//   - a required file does not exist
	//   - stdin or expected input source is unavailable
	ExitNoInput = 66

	// ExitUnavailable indicates that a required external service is unavailable.
	//
	// Use when:
	//   - database cannot be reached
	//   - Redis / Kafka / external API is down
	//   - network dependency is unreachable at startup
	//
	// This usually triggers restart in orchestration systems.
	ExitUnavailable = 69

	// ExitSoftware indicates an internal software error.
	//
	// Use when:
	//   - an invariant is violated
	//   - unexpected state is reached
	//   - a bug is detected but panic is not used
	ExitSoftware = 70

	// ExitOSError indicates an operating system error.
	//
	// Use when:
	//   - syscall failures occur
	//   - OS-level resources cannot be accessed
	ExitOSError = 71

	// ExitIOError indicates a low-level I/O failure.
	//
	// Use when:
	//   - disk read/write fails
	//   - socket I/O fails unexpectedly
	ExitIOError = 74

	// ExitTempFail indicates a temporary failure.
	//
	// Use when:
	//   - the operation can be retried
	//   - transient network issues occur
	//   - rate limits are hit
	//
	// Supervisors may retry automatically.
	ExitTempFail = 75

	// ExitNoPermission indicates insufficient permissions.
	//
	// Use when:
	//   - access to secrets is denied
	//   - filesystem permissions are insufficient
	//   - security constraints prevent startup
	ExitNoPermission = 77

	// ExitConfigError indicates an invalid configuration.
	//
	// Use when:
	//   - required environment variables are missing
	//   - configuration files are invalid or malformed
	//   - configuration values fail validation
	//
	// This is one of the most important exit codes for production systems.
	ExitConfigError = 78

	// ExitPanic indicates the application terminated due to a panic.
	//
	// Use when:
	//   - a panic was recovered in main()
	//   - an unrecoverable programming error occurred
	//
	// Panics SHOULD be treated differently from normal errors.
	ExitPanic = 10

	// ExitShutdownError indicates failure during graceful shutdown.
	//
	// Use when:
	//   - shutdown handlers exceed timeout
	//   - resources fail to close cleanly
	//
	// The application attempted to shut down gracefully but failed.
	ExitShutdownError = 20

	// ExitSignalBase is the base exit code for Unix signals.
	//
	// Actual exit code is calculated as:
	//   128 + signal number
	//
	// Examples:
	//   SIGINT  (2)  → 130
	//   SIGTERM (15) → 143
	//   SIGKILL (9)  → 137
	//
	// This value MUST NOT be returned manually.
	ExitSignalBase = 128
)

Variables

View Source
var (
	// Attempting to create a shutdown context but the root context has already been initialized.
	ErrContextAlreadyInit = errors.New("shutdown context already initialized")

	// Attempting to create a shutdown context with a nil parent.
	ErrParentContextNil = errors.New("parent context is nil")

	// Trying to add a shutdown handler after the shutdown process has started.
	ErrCannotAddHandlerAfterShutdown = errors.New("cannot add handler after shutdown started")

	// SetDefault is called after the default manager is already initialized.
	ErrManagerAlreadyRunning = errors.New("manager already runned")

	// SetDefault is called after shutdown has started or completed.
	ErrCannotCallAfterShutdown = errors.New("cannot call after shutdown started")

	// Unknown state is encountered.
	ErrUnknownState = errors.New("failed due to unknown state")
)

Functions

func AddHandler

func AddHandler(handler Handler) error

AddHandler registers a new shutdown handler.

A handler is a function that will be executed when the application is shutting down, either due to a system signal or a call to Shutdown()/Exit().

How it works:

1. The manager's state is checked:

  • If shutdown has not started yet, the handler is added to the list.

  • If shutdown is already in progress, adding a handler is not allowed and an error is returned.

    2. All registered handlers will be called during shutdown. They receive the root context and an exit code, allowing services to gracefully stop, release resources, and handle any cleanup or errors.

Constraints:

- Handlers can only be added before shutdown starts. - Any attempts to add handlers after shutdown has begun will fail.

Example:

err := shutdown.AddHandler(func(ctx context.Context, code int) error {
    log.Println("Closing database connection...")
    // perform cleanup
    return nil
})
if err != nil {
    log.Fatal(err)
}

func Context added in v0.7.0

func Context() context.Context

Context returns the root shutdown-aware context managed by this manager.

This function provides access to the application's root context, which is automatically canceled when the application begins shutting down. Using this context allows goroutines, workers, and services to detect shutdown events and stop gracefully.

How it works:

1. Checks if a shutdown context has been initialized:

  • If yes, returns the stored context.
  • If no, returns a default background context to ensure the caller always gets a valid context. 2. The returned context can be used anywhere in the application where a cancellable context is needed.

Constraints:

- The returned context is read-only; it should not be re-assigned or replaced. - The context may be canceled automatically during shutdown.

Example:

select {
case <-shutdown.Context().Done():
    // Shutdown signal received, stop work gracefully
default:
    // Continue normal operation
}

func Exit added in v0.7.0

func Exit(code int) int

Exit initiates the application shutdown process with the specified exit code and returns the resulting exit code once shutdown is complete.

This function performs the following steps:

  1. Initiates a graceful shutdown via Shutdown(code), notifying all registered shutdown handlers and cancelling the root context.
  2. Blocks the current goroutine until the shutdown process completes.
  3. Returns the final exit code to the caller.

Exit does NOT terminate the process itself. It is intended to be used as a convenience helper for initiating shutdown and propagating the exit code to the application entry point.

Important:

  • Exit blocks until all shutdown handlers have finished executing.
  • The caller is responsible for performing the actual process termination (for example, by calling os.Exit with the returned code).

Example:

func main() {
    code := shutdown.Exit(shutdown.ExitOK)
    os.Exit(code)
}

func NewContext added in v0.8.0

func NewContext() (context.Context, error)

NewContext creates a root, shutdown-aware context for the entire program.

In any Go application, the root context serves as the base for all other derived contexts. It is typically used to propagate cancellation signals and deadlines across multiple goroutines and services. `NewContext` ensures that the root context is properly initialized and protected from multiple concurrent creations.

This function wraps `WithContext(context.Background())` and returns a cancelable context that will be automatically canceled when the application initiates a shutdown, either manually via `Shutdown()`/`Exit()` or due to system signals (e.g., SIGINT, SIGTERM). Using this root context as the base for all other contexts ensures consistent handling of shutdown across the program.

Example:

ctx, err := shutdown.NewContext()
if err != nil {
    panic(err)
}
// pass `ctx` to servers, workers, or any long-running routines

By standardizing the creation of a root shutdown context, the application can gracefully cancel all operations and clean up resources consistently when shutting down.

func NewExitReason added in v0.12.0

func NewExitReason(code int, errs ...error) error

NewExitReason creates a new program termination reason with the specified exit code.

ExitReason represents a reason for program termination. It can wrap underlying errors (if provided) and associates them with a machine-readable exit code. This is useful for CLI applications or services where the process exit code matters (for orchestration, CI/CD, or supervisors).

The underlying errors `errs` can be omitted if you only want to signal an exit code without providing actual error messages.

Example:

// Exit with a software error and a descriptive message
return NewExitReason(ExitSoftware, fmt.Errorf("failed to initialize database"))

// Exit with just a code, no underlying error
return NewExitReason(ExitUnavailable)

func ParseExitReason added in v0.12.0

func ParseExitReason(e error) (int, bool)

ParseExitReason extracts the exit code and error presence from a wrapped ExitReason.

This function recursively unwraps the provided error `e` looking for ExitReason instances. It returns two values:

  • code: the most relevant exit code found (defaults to ExitGeneralError if none found)
  • hasErr: true if there is an actual underlying error, false if the ExitReason was just signaling a code

ParseExitReason is intended for CLI applications or services that need to translate error chains into appropriate exit codes for process termination.

Example usage:

// Simple case: just an ExitReason with a code
reason := NewExitReason(ExitUnavailable)
code, hasErr := ParseExitReason(reason)
fmt.Println(code, hasErr) // Output: ExitUnavailable, false
fmt.Println(reason.Error()) // Output: exit code: 69

// ExitReason wrapping an underlying error
reason = NewExitReason(ExitSoftware, fmt.Errorf("failed to initialize database"))
code, hasErr = ParseExitReason(reason)
fmt.Println(code, hasErr) // Output: ExitSoftware, true
fmt.Println(reason.Error()) // Output: failed to initialize database

// Nested ExitReasons: inner ExitReason can be preserved
reason1 := NewExitReason(ExitUnavailable, fmt.Errorf("reason1"))
reason2 := NewExitReason(ExitSoftware, fmt.Errorf("reason2: %w", reason1))
code, hasErr = ParseExitReason(reason2)
fmt.Println(code, hasErr) // Output: ExitUnavailable, true
fmt.Println(reason2.Error()) // Output: reason2: reason1

// No ExitReason in chain: defaults to general error
err := fmt.Errorf("just a normal error")
code, hasErr = ParseExitReason(err)
fmt.Println(code, hasErr) // Output: ExitGeneralError, true
fmt.Println(err.Error()) // Output: just a normal error

Use this function whenever you need a single exit code for the process while still capturing whether there was an actual error message to log or display.

func Recover added in v0.9.0

func Recover()

Recover intercepts panics that occur in the application, logs them, and initiates a graceful shutdown.

This function is used to protect the application from uncontrolled panics. If a panic occurs in any goroutine or part of the code, calling Recover() allows you to:

  • capture error information and the stack trace,
  • gracefully shut down the application via Exit() with a specific error code.

How it works:

1. Checks whether a panic has occurred in the current goroutine using the built-in recover() function. 2. If a panic is detected:

  • Logs a message including the panic details and stack trace.
  • Calls Exit() with a predefined panic exit code (ExitPanic) to terminate the application gracefully.

Example:

func main() {
    defer shutdown.Recover()

    // main application logic
    runServer()
}

func SetDefaultManager added in v0.11.0

func SetDefaultManager(m Manager) error

SetDefaultManager replaces the global default shutdown manager.

This function is intended mainly for testing or special scenarios where you need to provide a custom shutdown manager instead of the default one.

How it works:

1. It checks the current lifecycle state of the default manager:

  • If the manager has not yet been initialized, the custom manager is set.
  • If the manager is already running or shutdown has started, the call fails with an error. 2. After successfully setting the manager, it becomes the global default for all subsequent shutdown operations.

Constraints:

- Must be called before any call to Default(). - Cannot replace the manager after shutdown has started.

Example:

err := shutdown.SetDefaultManager(customMgr)
if err != nil {
    log.Fatal("failed to set custom shutdown manager:", err)
}

func SetShutdownTimeout added in v0.11.0

func SetShutdownTimeout(t time.Duration)

SetShutdownTimeout sets the maximum duration allowed for shutdown handlers to complete.

By default, each registered shutdown handler has a fixed amount of time to finish its work before being considered timed out. This function allows you to override that default timeout for the current shutdown manager.

How it works:

1. Sets the internal `timeout` used by the manager when executing shutdown handlers. 2. All subsequent calls to shutdown will use this new timeout value. 3. If handlers do not complete within the timeout, they are canceled, and a warning is logged.

Example:

// Allow handlers up to 5 seconds to complete
shutdown.SetShutdownTimeout(5 * time.Second)

Important:

- This timeout affects all handlers added before and after the call. - Should be called before triggering Shutdown/Exit for predictable behavior.

func Shutdown

func Shutdown(code int)

Shutdown initiates program termination with the specified exit code.

This function signals the manager that the application should shut down. It **does not block** execution at the call site — shutdown proceeds in the background, including execution of all registered shutdown handlers (graceful shutdown). The exit code will be used when the program finally terminates.

How it works:

1. Sends the exit code to the manager's internal channel. 2. The manager, in a separate goroutine, starts the graceful shutdown process:

  • cancels the root context,
  • runs all registered shutdown handlers,
  • exits the program with the specified code.

Constraints:

- Handlers may take some time to complete — shutdown proceeds asynchronously. - If the channel is blocked, the exit code might not be sent, and a warning is logged.

Example:

// Initiate shutdown with exit code 0 (shutdown.ExitOK)
shutdown.Shutdown(shutdown.ExitOK)
// Program execution continues; graceful shutdown runs in parallel

func Wait

func Wait() int

Wait blocks the current goroutine until a shutdown signal is received and returns the resulting exit code.

This function keeps the application running until a shutdown is initiated. It waits for one of the following events:

  • A call to Shutdown() or Exit() within the application code.
  • Receiving an OS termination signal (SIGINT, SIGTERM, SIGQUIT).

How it works:

  1. The function blocks until an exit code is sent to the internal exit channel.
  2. Once the code is received, it is returned to the caller.
  3. The function does NOT terminate the process itself.

Any registered shutdown handlers are executed before the exit code becomes available, as Shutdown/Exit triggers them beforehand.

It is the caller’s responsibility to decide how to handle the returned exit code (for example, by passing it to os.Exit in the application's entry point).

Example:

func main() {
    // Setup root context
    ctx, _ := shutdown.NewContext()

    // Add shutdown handlers
    shutdown.AddHandler(func(ctx context.Context, code int) error {
        log.Println("Closing database connections")
        return nil
    })

    // Wait for shutdown signal and handle exit code explicitly
    code := shutdown.Wait()
    os.Exit(code)
}

func WithContext added in v0.7.0

func WithContext(parent context.Context) (context.Context, error)

Types

type ExitReason added in v0.12.0

type ExitReason struct {
	Code int
	Err  error
}

func (*ExitReason) Error added in v0.12.0

func (e *ExitReason) Error() string

func (*ExitReason) Unwrap added in v0.12.0

func (e *ExitReason) Unwrap() error

type Handler added in v0.4.0

type Handler func(ctx context.Context, code int) error

type Manager added in v0.11.0

type Manager interface {
	NewContext() (context.Context, error)
	WithContext(parent context.Context) (context.Context, error)
	Context() context.Context
	AddHandler(handler Handler) error
	Wait() int
	Shutdown(code int)
	Exit(code int) int
	SetShutdownTimeout(t time.Duration)
}

type MockManager added in v0.11.0

type MockManager struct {
	mock.Mock
}

MockManager is an autogenerated mock type for the Manager type

func NewMockManager added in v0.11.0

func NewMockManager(t interface {
	mock.TestingT
	Cleanup(func())
}) *MockManager

NewMockManager creates a new instance of MockManager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. The first argument is typically a *testing.T value.

func (*MockManager) AddHandler added in v0.11.0

func (_mock *MockManager) AddHandler(handler Handler) error

AddHandler provides a mock function for the type MockManager

func (*MockManager) Context added in v0.11.0

func (_mock *MockManager) Context() context.Context

Context provides a mock function for the type MockManager

func (*MockManager) EXPECT added in v0.11.0

func (_m *MockManager) EXPECT() *MockManager_Expecter

func (*MockManager) Exit added in v0.11.0

func (_mock *MockManager) Exit(code int) int

Exit provides a mock function for the type MockManager

func (*MockManager) NewContext added in v0.11.0

func (_mock *MockManager) NewContext() (context.Context, error)

NewContext provides a mock function for the type MockManager

func (*MockManager) Recover added in v0.11.0

func (_mock *MockManager) Recover()

Recover provides a mock function for the type MockManager

func (*MockManager) SetShutdownTimeout added in v0.11.0

func (_mock *MockManager) SetShutdownTimeout(t time.Duration)

SetShutdownTimeout provides a mock function for the type MockManager

func (*MockManager) Shutdown added in v0.11.0

func (_mock *MockManager) Shutdown(code int)

Shutdown provides a mock function for the type MockManager

func (*MockManager) Wait added in v0.11.0

func (_mock *MockManager) Wait() int

Wait provides a mock function for the type MockManager

func (*MockManager) WithContext added in v0.11.0

func (_mock *MockManager) WithContext(parent context.Context) (context.Context, error)

WithContext provides a mock function for the type MockManager

type MockManager_AddHandler_Call added in v0.11.0

type MockManager_AddHandler_Call struct {
	*mock.Call
}

MockManager_AddHandler_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddHandler'

func (*MockManager_AddHandler_Call) Return added in v0.11.0

func (*MockManager_AddHandler_Call) Run added in v0.11.0

func (*MockManager_AddHandler_Call) RunAndReturn added in v0.11.0

func (_c *MockManager_AddHandler_Call) RunAndReturn(run func(handler Handler) error) *MockManager_AddHandler_Call

type MockManager_Context_Call added in v0.11.0

type MockManager_Context_Call struct {
	*mock.Call
}

MockManager_Context_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Context'

func (*MockManager_Context_Call) Return added in v0.11.0

func (*MockManager_Context_Call) Run added in v0.11.0

func (*MockManager_Context_Call) RunAndReturn added in v0.11.0

func (_c *MockManager_Context_Call) RunAndReturn(run func() context.Context) *MockManager_Context_Call

type MockManager_Exit_Call added in v0.11.0

type MockManager_Exit_Call struct {
	*mock.Call
}

MockManager_Exit_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Exit'

func (*MockManager_Exit_Call) Return added in v0.11.0

func (*MockManager_Exit_Call) Run added in v0.11.0

func (_c *MockManager_Exit_Call) Run(run func(code int)) *MockManager_Exit_Call

func (*MockManager_Exit_Call) RunAndReturn added in v0.11.0

func (_c *MockManager_Exit_Call) RunAndReturn(run func(code int) int) *MockManager_Exit_Call

type MockManager_Expecter added in v0.11.0

type MockManager_Expecter struct {
	// contains filtered or unexported fields
}

func (*MockManager_Expecter) AddHandler added in v0.11.0

func (_e *MockManager_Expecter) AddHandler(handler interface{}) *MockManager_AddHandler_Call

AddHandler is a helper method to define mock.On call

  • handler Handler

func (*MockManager_Expecter) Context added in v0.11.0

Context is a helper method to define mock.On call

func (*MockManager_Expecter) Exit added in v0.11.0

func (_e *MockManager_Expecter) Exit(code interface{}) *MockManager_Exit_Call

Exit is a helper method to define mock.On call

  • code int

func (*MockManager_Expecter) NewContext added in v0.11.0

NewContext is a helper method to define mock.On call

func (*MockManager_Expecter) Recover added in v0.11.0

Recover is a helper method to define mock.On call

func (*MockManager_Expecter) SetShutdownTimeout added in v0.11.0

func (_e *MockManager_Expecter) SetShutdownTimeout(t interface{}) *MockManager_SetShutdownTimeout_Call

SetShutdownTimeout is a helper method to define mock.On call

  • t time.Duration

func (*MockManager_Expecter) Shutdown added in v0.11.0

func (_e *MockManager_Expecter) Shutdown(code interface{}) *MockManager_Shutdown_Call

Shutdown is a helper method to define mock.On call

  • code int

func (*MockManager_Expecter) Wait added in v0.11.0

Wait is a helper method to define mock.On call

func (*MockManager_Expecter) WithContext added in v0.11.0

func (_e *MockManager_Expecter) WithContext(parent interface{}) *MockManager_WithContext_Call

WithContext is a helper method to define mock.On call

  • parent context.Context

type MockManager_NewContext_Call added in v0.11.0

type MockManager_NewContext_Call struct {
	*mock.Call
}

MockManager_NewContext_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewContext'

func (*MockManager_NewContext_Call) Return added in v0.11.0

func (*MockManager_NewContext_Call) Run added in v0.11.0

func (*MockManager_NewContext_Call) RunAndReturn added in v0.11.0

type MockManager_Recover_Call added in v0.11.0

type MockManager_Recover_Call struct {
	*mock.Call
}

MockManager_Recover_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Recover'

func (*MockManager_Recover_Call) Return added in v0.11.0

func (*MockManager_Recover_Call) Run added in v0.11.0

func (*MockManager_Recover_Call) RunAndReturn added in v0.11.0

func (_c *MockManager_Recover_Call) RunAndReturn(run func()) *MockManager_Recover_Call

type MockManager_SetShutdownTimeout_Call added in v0.11.0

type MockManager_SetShutdownTimeout_Call struct {
	*mock.Call
}

MockManager_SetShutdownTimeout_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetShutdownTimeout'

func (*MockManager_SetShutdownTimeout_Call) Return added in v0.11.0

func (*MockManager_SetShutdownTimeout_Call) Run added in v0.11.0

func (*MockManager_SetShutdownTimeout_Call) RunAndReturn added in v0.11.0

type MockManager_Shutdown_Call added in v0.11.0

type MockManager_Shutdown_Call struct {
	*mock.Call
}

MockManager_Shutdown_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Shutdown'

func (*MockManager_Shutdown_Call) Return added in v0.11.0

func (*MockManager_Shutdown_Call) Run added in v0.11.0

func (_c *MockManager_Shutdown_Call) Run(run func(code int)) *MockManager_Shutdown_Call

func (*MockManager_Shutdown_Call) RunAndReturn added in v0.11.0

func (_c *MockManager_Shutdown_Call) RunAndReturn(run func(code int)) *MockManager_Shutdown_Call

type MockManager_Wait_Call added in v0.11.0

type MockManager_Wait_Call struct {
	*mock.Call
}

MockManager_Wait_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Wait'

func (*MockManager_Wait_Call) Return added in v0.11.0

func (*MockManager_Wait_Call) Run added in v0.11.0

func (_c *MockManager_Wait_Call) Run(run func()) *MockManager_Wait_Call

func (*MockManager_Wait_Call) RunAndReturn added in v0.11.0

func (_c *MockManager_Wait_Call) RunAndReturn(run func() int) *MockManager_Wait_Call

type MockManager_WithContext_Call added in v0.11.0

type MockManager_WithContext_Call struct {
	*mock.Call
}

MockManager_WithContext_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithContext'

func (*MockManager_WithContext_Call) Return added in v0.11.0

func (*MockManager_WithContext_Call) Run added in v0.11.0

func (*MockManager_WithContext_Call) RunAndReturn added in v0.11.0

Jump to

Keyboard shortcuts

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