« Back to Index

[Go defer cleanup exit pattern]

View original Gist on GitHub

Tags: #tags: go, golang, pattern, cleanup

go defer cleanup exit pattern.md

Taken from Go Programming Blueprints (second edition)

package main 

import ( 
  "flag" 
  "fmt" 
  "os" 
) 
var fatalErr error 
func fatal(e error) { 
  fmt.Println(e) 
  flag.PrintDefaults() 
  fatalErr = e 
} 
func main() { 
  defer func() { 
    if fatalErr != nil { 
      os.Exit(1) 
    } 
  }() 
} 

Normally when we encounter an error in our code, we use a call such as log.Fatal or os.Exit, which immediately terminates the program. Exiting the program with a nonzero exit code is important because it is our way of telling the operating system that something went wrong, and we didn’t complete our task successfully. The problem with the normal approach is that any deferred functions we have scheduled (and therefore any teardown code we need to run) won’t get a chance to execute.

The pattern employed in the preceding code snippet lets us call the fatal function to record that an error has occurred. Note that only when our main function exits will the deferred function run, which in turn calls os.Exit(1) to exit the program with an exit code of 1. Because the deferred statements are run in LIFO (last in, first out) order, the first function we defer will be the last function to be executed, which is why the first thing we do in the main function is defer the exiting code. This allows us to be sure that other functions we defer will be called before the program exits. We’ll use this feature to ensure that our database connection gets closed regardless of any errors.