Documentation
¶
Overview ¶
Package shutdown provides management of your shutdown process.
The package will enable you to get notifications for your application and handle the shutdown process.
See more information about the how to use it in the README.md file ¶
Package home: https://github.com/klauspost/shutdown2
Example (Functions) ¶
Get a notifier and perform our own function when we shutdown
_ = FirstFn(func() { // This function is called on shutdown fmt.Println("First shutdown stage called") }) // Will print the parameter when Shutdown() is called
Output:
Index ¶
- Variables
- func CancelCtx(parent context.Context) (ctx context.Context, cancel context.CancelFunc)
- func CancelCtxN(parent context.Context, s Stage) (ctx context.Context, cancel context.CancelFunc)
- func Exit(code int)
- func Lock(ctx ...interface{}) func()
- func OnSignal(exitCode int, sig ...os.Signal)
- func OnTimeout(fn func(Stage, string))
- func SetLogPrinter(fn func(format string, v ...interface{}))
- func SetTimeout(d time.Duration)
- func SetTimeoutN(s Stage, d time.Duration)
- func Shutdown()
- func Started() bool
- func Wait()
- func WrapHandler(h http.Handler) http.Handler
- func WrapHandlerFunc(h http.HandlerFunc) http.HandlerFunc
- type LogPrinter
- type Notifier
- func First(ctx ...interface{}) Notifier
- func FirstFn(fn func(), ctx ...interface{}) Notifier
- func PreShutdown(ctx ...interface{}) Notifier
- func PreShutdownFn(fn func(), ctx ...interface{}) Notifier
- func Second(ctx ...interface{}) Notifier
- func SecondFn(fn func(), ctx ...interface{}) Notifier
- func Third(ctx ...interface{}) Notifier
- func ThirdFn(fn func(), ctx ...interface{}) Notifier
- type Stage
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // Logger used for output. // This can be exchanged with your own. Logger = LogPrinter(log.New(os.Stderr, "[shutdown]: ", log.LstdFlags)) // LoggerMu is a mutex for the Logger LoggerMu sync.Mutex // StagePS indicates the pre shutdown stage when waiting for locks to be released. StagePS = Stage{0} // Stage1 Indicates first stage of timeouts. Stage1 = Stage{1} // Stage2 Indicates second stage of timeouts. Stage2 = Stage{2} // Stage3 indicates third stage of timeouts. Stage3 = Stage{3} // WarningPrefix is printed before warnings. WarningPrefix = "WARN: " // ErrorPrefix is printed before errors. ErrorPrefix = "ERROR: " // LogLockTimeouts enables log timeout warnings // and notifier status updates. // Should not be changed once shutdown has started. LogLockTimeouts = true // StatusTimer is the time between logging which notifiers are waiting to finish. // Should not be changed once shutdown has started. StatusTimer = time.Minute )
Functions ¶
func CancelCtx ¶
CancelCtx will cancel the supplied context when shutdown starts. The returned context must be cancelled when done similar to https://golang.org/pkg/context/#WithCancel
func CancelCtxN ¶
CancelCtxN will cancel the supplied context at a supplied shutdown stage. The returned context must be cancelled when done similar to https://golang.org/pkg/context/#WithCancel
func Exit ¶
func Exit(code int)
Exit performs shutdown operations and exits with the given exit code.
func Lock ¶
func Lock(ctx ...interface{}) func()
Lock will signal that you have a function running, that you do not want to be interrupted by a shutdown.
The lock is created with a timeout equal to the length of the preshutdown stage at the time of creation. When that amount of time has expired the lock will be removed, and a warning will be printed.
If the function returns nil shutdown has already been initiated, and you did not get a lock. You should therefore not call the returned function.
If the function did not return nil, you should call the function to unlock the lock.
You should not hold a lock when you start a shutdown.
For easier debugging you can send a context that will be printed if the lock times out. All supplied context is printed with '%v' formatting.
Example ¶
Note that the same effect of this example can also be achieved using the WrapHandlerFunc helper.
http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { // Get a lock while we have the lock, the server will not shut down. lock := Lock() if lock != nil { defer lock() } else { // We are currently shutting down, return http.StatusServiceUnavailable w.WriteHeader(http.StatusServiceUnavailable) return } // ... }) http.ListenAndServe(":8080", nil)
Output:
func OnSignal ¶
OnSignal will start the shutdown when any of the given signals arrive
A good shutdown default is
shutdown.OnSignal(0, os.Interrupt, syscall.SIGTERM)
which will do shutdown on Ctrl+C and when the program is terminated.
func OnTimeout ¶ added in v1.1.0
OnTimeout allows you to get a notification if a shutdown stage times out. The stage and the context of the hanging shutdown/lock function is returned.
func SetLogPrinter ¶
func SetLogPrinter(fn func(format string, v ...interface{}))
SetLogPrinter will use the specified function to write logging information.
func SetTimeout ¶
SetTimeout sets maximum delay to wait for each stage to finish. When the timeout has expired for a stage the next stage will be initiated.
func SetTimeoutN ¶
SetTimeoutN set maximum delay to wait for a specific stage to finish. When the timeout expired for a stage the next stage will be initiated. The stage can be obtained by using the exported variables called 'Stage1, etc.
Example ¶
Change timeout for a single stage
// Set timout for all stages SetTimeout(time.Second) // But give second stage more time SetTimeoutN(Stage2, time.Second*10)
Output:
func Shutdown ¶
func Shutdown()
Shutdown will signal all notifiers in three stages. It will first check that all locks have been released - see Lock()
func Started ¶
func Started() bool
Started returns true if shutdown has been started. Note that shutdown can have been started before you check the value.
func Wait ¶
func Wait()
Wait will wait until shutdown has finished. This can be used to keep a main function from exiting until shutdown has been called, either by a goroutine or a signal.
Example ¶
This is an example, that could be your main function.
We wait for jobs to finish in another goroutine, from where we initialize the shutdown.
This is of course not a real-world problem, but there are many cases where you would want to initialize shutdown from other places than your main function, and where you would still like it to be able to do some final cleanup.
x := make([]struct{}, 10) var wg sync.WaitGroup wg.Add(len(x)) for i := range x { go func(i int) { time.Sleep(time.Millisecond * time.Duration(i)) wg.Done() }(i) } // ignore this reset, for test purposes only reset() // Wait for the jobs above to finish go func() { wg.Wait() fmt.Println("jobs done") Shutdown() }() // Since this is main, we wait for a shutdown to occur before // exiting. Wait() fmt.Println("exiting main") // Note than the output will always be in this order.
Output: jobs done exiting main
func WrapHandler ¶
WrapHandler will return an http Handler That will lock shutdown until all have completed and will return http.StatusServiceUnavailable if shutdown has been initiated.
Example ¶
This example creates a fileserver and wraps the handler, so all request will finish before shutdown is started.
If requests take too long to finish the shutdown will proceed and clients will be disconnected when the server shuts down. To modify the timeout use SetTimeoutN(Preshutdown, duration)
// Set a custom timeout, if the 5 second default doesn't fit your needs. SetTimeoutN(StagePS, time.Second*30) // Catch OS signals OnSignal(0, os.Interrupt, syscall.SIGTERM) // Create a fileserver handler fh := http.FileServer(http.Dir("/examples")) // Wrap the handler function http.Handle("/", WrapHandler(fh)) // Start the server http.ListenAndServe(":8080", nil)
Output:
func WrapHandlerFunc ¶
func WrapHandlerFunc(h http.HandlerFunc) http.HandlerFunc
WrapHandlerFunc will return an http.HandlerFunc that will lock shutdown until all have completed. The handler will return http.StatusServiceUnavailable if shutdown has been initiated.
Example ¶
This example creates a custom function handler and wraps the handler, so all request will finish before shutdown is started.
If requests take too long to finish (see the shutdown will proceed and clients will be disconnected when the server shuts down. To modify the timeout use SetTimeoutN(Preshutdown, duration)
// Set a custom timeout, if the 5 second default doesn't fit your needs. SetTimeoutN(StagePS, time.Second*30) // Catch OS signals OnSignal(0, os.Interrupt, syscall.SIGTERM) // Example handler function fn := func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path)) } // Wrap the handler function http.HandleFunc("/", WrapHandlerFunc(fn)) // Start the server http.ListenAndServe(":8080", nil)
Output:
Types ¶
type LogPrinter ¶
type LogPrinter interface {
Printf(format string, v ...interface{})
}
LogPrinter is an interface for writing logging information. The writer must handle concurrent writes.
type Notifier ¶
type Notifier chan chan struct{}
Notifier is a channel, that will be sent a channel once the application shuts down. When you have performed your shutdown actions close the channel you are given.
Example ¶
Get a notifier and perform our own code when we shutdown
shutdown := First() select { case n := <-shutdown: // Do shutdown code ... // Signal we are done close(n) }
Output:
func First ¶
func First(ctx ...interface{}) Notifier
First returns a notifier that will be called in the first stage of shutdowns. If shutdown has started and this stage has already been reached, nil will be returned. The context is printed if LogLockTimeouts is enabled.
func FirstFn ¶
func FirstFn(fn func(), ctx ...interface{}) Notifier
FirstFn executes a function in the first stage of the shutdown If shutdown has started and this stage has already been reached, nil will be returned. The context is printed if LogLockTimeouts is enabled.
func PreShutdown ¶
func PreShutdown(ctx ...interface{}) Notifier
PreShutdown will return a Notifier that will be fired as soon as the shutdown. is signalled, before locks are released. This allows to for instance send signals to upstream servers not to send more requests. The context is printed if LogLockTimeouts is enabled.
func PreShutdownFn ¶
func PreShutdownFn(fn func(), ctx ...interface{}) Notifier
PreShutdownFn registers a function that will be called as soon as the shutdown. is signalled, before locks are released. This allows to for instance send signals to upstream servers not to send more requests. The context is printed if LogLockTimeouts is enabled.
func Second ¶
func Second(ctx ...interface{}) Notifier
Second returns a notifier that will be called in the second stage of shutdowns. If shutdown has started and this stage has already been reached, nil will be returned. The context is printed if LogLockTimeouts is enabled.
func SecondFn ¶
func SecondFn(fn func(), ctx ...interface{}) Notifier
SecondFn executes a function in the second stage of the shutdown. If shutdown has started and this stage has already been reached, nil will be returned. The context is printed if LogLockTimeouts is enabled.
func Third ¶
func Third(ctx ...interface{}) Notifier
Third returns a notifier that will be called in the third stage of shutdowns. If shutdown has started and this stage has already been reached, nil will be returned. The context is printed if LogLockTimeouts is enabled.
func ThirdFn ¶
func ThirdFn(fn func(), ctx ...interface{}) Notifier
ThirdFn executes a function in the third stage of the shutdown. If shutdown has started and this stage has already been reached, nil will be returned. The context is printed if LogLockTimeouts is enabled.
func (Notifier) Cancel ¶
func (s Notifier) Cancel()
Cancel a Notifier. This will remove a notifier from the shutdown queue, and it will not be signalled when shutdown starts. If the shutdown has already started this will not have any effect, but a goroutine will wait for the notifier to be triggered.
func (Notifier) CancelWait ¶
func (s Notifier) CancelWait()
CancelWait will cancel a Notifier, or wait for it to become active if shutdown has been started. This will remove a notifier from the shutdown queue, and it will not be signalled when shutdown starts. If the notifier is nil (requested after its stage has started), it will return at once. If the shutdown has already started, this will wait for the notifier to be called and close it.