Exit with a status
Exit with a status using os.Exit(n). It ends the program at once and skips every deferred call, so cleanup in defer is not run before the exit.
A program exits with a failure status and the cleanup in its deferred calls never happens.
package main
import (
"fmt"
"os"
)
func main() {
defer fmt.Println("deferred: cleanup ran")
fmt.Println("working")
if len(os.Args) > 1 {
os.Exit(3)
}
}go build -o app main.go
./app; echo "status $?"
echo ---
./app fail; echo "status $?"working
deferred: cleanup ran
status 0
---
working
status 3os.Exit terminates the process immediately with the status it is given, without unwinding the stack, so deferred functions do not run and buffered output is not flushed. Returning from main runs them and exits with 0. This is stated in the os package documentation. log.Fatal calls os.Exit(1) the same way. The second run above prints no deferred line.
Keep the work in a run() error function and call os.Exit once in main after it returns, so every defer has run. go run hides the code: it prints "exit status 3" and exits with 1, so build the binary to see the real value. Statuses above 255 wrap around on Unix.