Exit with error code in go?
Solution 1
I do something along these lines in most of my real main
packages, so that the return err
convention is adopted as soon as possible, and has a proper termination:
func main() {
if err := run(); err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
}
func run() error {
err := something()
if err != nil {
return err
}
// etc
}
Solution 2
In python I commonly use pattern which converted to go looks like this:
func run() int {
// here goes
// the code
return 1
}
func main() {
os.Exit(run())
}
Solution 3
I think the most clear way to do it is to set the exitCode
at the top of main
, then defer
closing as the next step. That lets you change exitCode
anywhere in main
, and it's last value will be exited with:
package main
import (
"fmt"
"os"
)
func main() {
exitCode := 0
defer func() { os.Exit(exitCode) }()
// Do whatever, including deferring more functions
defer func() {
fmt.Printf("Do some cleanup\n")
}()
func() {
fmt.Printf("Do some work\n")
}()
// But let's say something went wrong
exitCode = 1
// Do even more work/cleanup if you want
// At the end, os.Exit will be called with the last value of exitCode
}
Output:
Do some work
Do some cleanup
Program exited: status 1.
Go Playgroundhttps://play.golang.org/p/AMUR4m_A9Dw
Note that an important disadvantage of this is that you don't exit the process as soon as you set the error code.
Solution 4
As mentioned by fas, you have func Exit(exitcode int)
from the os package.
However, if you need the defered function to be applied, you always can use the defer
keyword like this:
http://play.golang.org/p/U-hAS88Ug4
You perform all your operation, affect a error variable and at the very end, when everything is cleaned up, you can exit safely.
Otherwise, you could also use panic/recover: http://play.golang.org/p/903e76GnQ-
When you have an error, you panic, end you cleanup where you catch (recover) it.
dan
Updated on July 05, 2022Comments
-
dan almost 2 years
What's the idiomatic way to exit a program with some error code?
The documentation for
Exit
says "The program terminates immediately; deferred functions are not run.", andlog.Fatal
just callsExit
. For things that aren't heinous errors, terminating the program without running deferred functions seems extreme.Am I supposed to pass around some state that indicate that there's been an error, and then call
Exit(1)
at some point where I know that I can exit safely, with all deferred functions having been run? -
topskip almost 11 yearsI am pretty sure @dan knows about it.
-
d1str0 almost 11 yearsMaybe I misread or he edited but I thought he was talking about something else.
-
marczoid over 8 yearsI think I understand what you mean in the first approach, but the example is a little confusing to me. Why defer fct1() and fct2()? This mean that they will be executed in reverse order! It seems you intend something more like this, or not?
-
Loupax almost 4 yearsI consider this the best solution. You can return an error from the
run()
method and havemain()
deal with it without how it sees fit. -
Ben over 3 yearsLeaving this up, but after writing more Go code I think stackoverflow.com/a/18969976/2958070 (answer by Gustavo Niemeyer) is clearer and easier to use in basically all cases. Keeping track of function calls is a lot easier than keeping track of defers
-
sprut about 3 yearsWhat's the best method to test this code?
-
Gustavo Niemeyer about 3 yearsRun the binary in a functional test.
-
emlai over 2 years
_, _ = fmt.Fprintf(…)
to explicitly ignore the error returned by Fprintf. -
Mitar over 2 yearsA downside of this approach is that if your code panics, it will never be printed out, because before panic propagates to the top, you exit the program in defer.