closer

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

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

Go to latest
Published: Mar 10, 2022 License: Apache-2.0 Imports: 2 Imported by: 9

README

Go Closer

Go Closer provides utility functions for closing resources in Go.

Ensuring a resource is always closed

To ensure a resource is always closed in Go, it is common practice to defer a call to close the resource immediately after opening it successfully. Consider an openResource function with three return values: a resource, a callback function to close the resource, and an error if the resource could not be opened. A common practice is to write the following:

func f() error {
  res, closeFn, err := openResource()
  if err != nil {
    return nil, err
  }
  defer closeFn()
  return useResource(res)
}

However, this solution is less satisfying in the case that the closeFn callback can itself return an error. In such cases, it is appropriate to use closer.Close or closer.CloseAndLog to ensure the resource is closed but the error is still surfaced in some way. An example use of closer.Close:

func f() (rerr error) {
  res, closeFn, err := openResource()
  if err != nil {
    return nil, err
  }
  defer closer.Close(&rerr, closeFn, "error closing resource")
  return useResource(res)
}

The deferred closer.Close ensures:

  1. That closeFn is called regardless of the outcome of useResource -- whether it returns normally, with an error, or raises a panic.
  2. If both useResource and closeFn return errors, f returns the same error as useResource and the error returned by closeFn is logged.
  3. If closeFn returns an error but useResource does not, f returns the same error as closeFn.

There are cases in which that last property may not be desirable. That is, you may not want to return the error produced by closeFn even when useResource has returned normally. Perhaps you agree with the argument that returning an error on close should only be done when writing to a resource, not when reading. Or perhaps the outer function f complies with an interface that doesn't permit returning an error. In these cases, use closer.CloseAndLog to unconditionally log any error returned by closeFn:

func f() error {
  res, closeFn, err := openResource()
  if err != nil {
    return nil, err
  }
  defer closer.CloseAndLog(closeFn, "error closing resource")
  return useResource(res)
}

Ensuring a resource is closed only when there's a subsequent error

Sometimes a function intends to leave a resource open when it returns normally but wishes to close it in the case it returns an error. For such cases, use closer.CloseOnErr or closer.CloseVoidOnErr. An example:

func f() (val Value, rerr error) {
  res, closeFn, err := openResource()
  if err != nil {
    return nil, err
  }
  defer closer.CloseOnErr(&rerr, closeFn, "error closing resource")
  return wrapResource(res)
}

Documentation

Overview

Package closer provides a utility for closing resources.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Close

func Close(rerr *error, fn func() error, msg string)

Close runs the given close function, assigning the close error, if any, to rerr if rerr is non-nil. If rerr is nil, the error is logged. Must be called in a defer on a return value of exactly "&rerr".

func CloseAndLog

func CloseAndLog(fn func() error, msg string)

CloseAndLog runs the given close function and logs the close error, if any. Must be called in a defer.

func CloseOnErr

func CloseOnErr(rerr *error, fn func() error, msg string)

CloseOnErr runs the given close function if rerr is not-nil. The close error, if any, is logged. Must be called in a defer on a return value of exactly "&rerr".

func CloseVoidOnErr

func CloseVoidOnErr(rerr *error, fn func())

CloseVoidOnErr runs the given close function if rerr is not-nil. Must be called in a defer on a return value of exactly "&rerr".

Types

This section is empty.

Jump to

Keyboard shortcuts

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