deferexit

package module
v0.0.0-...-1397452 Latest Latest
Warning

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

Go to latest
Published: Apr 30, 2026 License: GPL-3.0 Imports: 0 Imported by: 0

README

Defer-Friendly Program Exit

GoDoc Build Status codecov

The deferexit Go package implements panic-based program exit so that deferred cleanup (lockfile release, marker cleanup, temp file removal, etc.) actually runs before the process terminates.

Calling os.Exit directly from main skips all defers registered up the stack. This package replaces that pattern with a typed panic that the outermost main recovers from and converts into a real os.Exit, after every deferred function has run.

import (
	"os"

	"github.com/bassosimone/deferexit"
)

func main() {
	defer deferexit.Recover(os.Exit)
	realMain()
}

func realMain() {
	defer cleanup() // actually runs, even on the failure path

	if somethingWrong() {
		deferexit.Panic(2) // unwinds the stack instead of os.Exit(2)
	}
}

deferexit.Run is a test-only helper that runs a main-like function and returns the exit code carried by any Panic raised inside it (or zero if it returned normally). Production main should NOT be written as os.Exit(Run(realMain)): that pattern calls os.Exit unconditionally even on the success path, which makes main untestable. See the package documentation for details.

Installation

To add this package as a dependency to your module:

go get github.com/bassosimone/deferexit

Development

To run the tests:

go test -v .

To measure test coverage:

go test -v -cover .

License

SPDX-License-Identifier: GPL-3.0-or-later

History

This package graduated from bassosimone/npte, where it was originally introduced. It was promoted to its own module to be reusable across unrelated projects that share the same need for defer-friendly program exit.

Documentation

Overview

Package deferexit implements panic-based program exit so that deferred cleanup runs before the process actually terminates.

Code that wants to abort the program calls Panic instead of os.Exit. The outermost main function installs `defer Recover(os.Exit)`, which catches the typed panic raised by Panic and converts it back to a real process exit after every deferred function has run.

Run is a convenience wrapper that runs a function and returns the exit code carried by any Panic raised inside it (or zero if the function returns normally). It is intended for tests that want to assert on the exit code that a main-like function would have produced.

Production main should NOT be written as `os.Exit(Run(realMain))`: that pattern calls os.Exit unconditionally even when realMain returns normally, which makes the success path of main untestable (any test that calls main would terminate the test binary). The recommended production pattern is:

func main() {
	defer deferexit.Recover(os.Exit)
	realMain()
}

which only reaches os.Exit when Panic was actually raised.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Panic

func Panic(code int)

Panic panics with a Code value carrying the given exit code. Use this instead of os.Exit so that deferred functions (lockfile release, marker cleanup, etc.) run before the process terminates.

func Recover

func Recover(onExit func(code int))

Recover catches a Code panic raised via Panic and calls onExit with the carried code. Any other panic value is re-raised so that real programmer bugs still produce the standard Go panic output.

Use it as `defer deferexit.Recover(os.Exit)` at the top of main.

func Run

func Run(fx func()) (exitcode int)

Run runs fx and returns the exit code carried by any Panic raised inside fx, or zero if fx returned normally. Non-Code panics are re-raised so real bugs are not swallowed.

Use this in tests to assert on the exit code that a main-like function would have produced. See the package documentation for why production main should not be written as `os.Exit(Run(...))`.

Types

type Code

type Code int

Code is the exit code carried by panics raised via Panic.

Jump to

Keyboard shortcuts

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