Documentation ¶
Overview ¶
Package graterm provides capabilities to create a Terminator instance, register ordered termination Hooks, and block application execution until one of the registered os.Signal events occurs.
Termination hooks registered with the same Order will be executed concurrently.
It is possible to set individual timeouts for each registered termination hook and global termination timeout for the whole application.
Optionally a Hook may have a name (using Hook.WithName). It might be handy only if the Logger injected into Terminator instance to log internal termination lifecycle events.
Examples ¶
Example code for generic application components:
func main() { // Define termination Orders: const ( HTTPServerTerminationOrder graterm.Order = 1 DBTerminationOrder graterm.Order = 2 ) // create new Terminator instance: terminator, appCtx := graterm.NewWithSignals(context.Background(), syscall.SIGINT, syscall.SIGTERM) terminator.SetLogger(log.Default()) // Optional step // Register HTTP Server termination hook: terminator.WithOrder(HTTPServerTerminationOrder). WithName("HTTP Server"). // setting a Name is optional and will be useful only if logger instance provided Register(1*time.Second, func(ctx context.Context) { log.Println("terminating HTTP Server...") defer log.Println("...HTTP Server terminated") }) // Register nameless DB termination hook: terminator.WithOrder(DBTerminationOrder). Register(1*time.Second, func(ctx context.Context) { log.Println("terminating Database...") defer log.Println("...Database terminated") const sleepTime = 3 * time.Second select { case <-time.After(sleepTime): log.Printf("Database termination sleep time %v is over\n", sleepTime) case <-ctx.Done(): log.Printf("Database termination Context is Done because of: %+v\n", ctx.Err()) } }) // Wait for os.Signal to occur, then terminate application with maximum timeout of 20 seconds: if err := terminator.Wait(appCtx, 20*time.Second); err != nil { log.Printf("graceful termination period was timed out: %+v", err) } }
Example code for HTTP server integration:
func main() { // Define Order for HTTP Server termination: const HTTPServerTerminationOrder graterm.Order = 1 // create new Terminator instance: terminator, appCtx := graterm.NewWithSignals(context.Background(), syscall.SIGINT, syscall.SIGTERM) terminator.SetLogger(log.Default()) // Optional step // Create an HTTP Server and add one simple handler into it: httpServer := &http.Server{ ReadHeaderTimeout: 60 * time.Second, // fix for potential Slowloris Attack Addr: ":8080", Handler: http.DefaultServeMux, } http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "hello, world!") }) // Start HTTP server in a separate goroutine: go func() { if err := httpServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { log.Printf("terminated HTTP Server: %+v\n", err) } }() // Register HTTP Server termination hook: terminator.WithOrder(HTTPServerTerminationOrder). WithName("HTTPServer"). // setting a Name is optional and will be useful only if logger instance provided Register(10*time.Second, func(ctx context.Context) { if err := httpServer.Shutdown(ctx); err != nil { log.Printf("shutdown HTTP Server: %+v\n", err) } }) // Wait for os.Signal to occur, then terminate application with maximum timeout of 30 seconds: if err := terminator.Wait(appCtx, 30*time.Second); err != nil { log.Printf("graceful termination period is timed out: %+v\n", err) } }
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Hook ¶ added in v0.4.0
type Hook struct {
// contains filtered or unexported fields
}
Hook is a registered ordered termination unit of work. I.e., the code that needs to be executed to perform resource cleanup or any other maintenance while shutting down the application.
Do NOT create a Hook instance manually, use Terminator.WithOrder() method instead to get a Hook instance.
func (*Hook) Register ¶ added in v0.4.0
Register registers termination Hook that should finish execution in less than given timeout.
Timeout duration must be greater than zero; if not, timeout of 1 min will be used.
The context value passed into hookFunc will be used only for cancellation signaling. I.e. to signal that Terminator will no longer wait on Hook to finish termination.
Example ¶
package main import ( "context" "log" "syscall" "time" "github.com/skovtunenko/graterm" ) func main() { // Define Order: const ( HTTPServerTerminationOrder graterm.Order = 1 ) // create new Terminator instance: terminator, appCtx := graterm.NewWithSignals(context.Background(), syscall.SIGINT, syscall.SIGTERM) // Register some hooks: terminator.WithOrder(HTTPServerTerminationOrder). Register(1*time.Second, func(ctx context.Context) { log.Println("terminating HTTP Server...") defer log.Println("...HTTP Server terminated") }) // Wait for os.Signal to occur, then terminate application with maximum timeout of 20 seconds: if err := terminator.Wait(appCtx, 20*time.Second); err != nil { log.Printf("graceful termination period was timed out: %+v", err) } }
Output:
func (*Hook) WithName ¶ added in v0.4.0
WithName sets (optional) human-readable name of the registered termination Hook.
The Hook name will be useful only if Logger instance has been injected (using Terminator.SetLogger method) into Terminator to log internal termination lifecycle events.
Example ¶
package main import ( "context" "log" "syscall" "time" "github.com/skovtunenko/graterm" ) func main() { // Define Order: const ( HTTPServerTerminationOrder graterm.Order = 1 ) // create new Terminator instance: terminator, appCtx := graterm.NewWithSignals(context.Background(), syscall.SIGINT, syscall.SIGTERM) terminator.SetLogger(log.Default()) // Optional step // Register some hooks: terminator.WithOrder(HTTPServerTerminationOrder). WithName("HTTP Server"). // Define (optional) Hook name Register(1*time.Second, func(ctx context.Context) { log.Println("terminating HTTP Server...") defer log.Println("...HTTP Server terminated") }) // Wait for os.Signal to occur, then terminate application with maximum timeout of 20 seconds: if err := terminator.Wait(appCtx, 20*time.Second); err != nil { log.Printf("graceful termination period was timed out: %+v", err) } }
Output:
type Logger ¶
type Logger interface {
Printf(format string, v ...interface{})
}
Logger specifies the interface for internal Terminator log operations.
By default, library will not log anything. To set the logger, use Terminator.SetLogger() method.
type Order ¶ added in v0.4.0
type Order int
Order is an application components termination order. Termination Hooks registered with the same order will be executed concurrently.
Lower order - higher priority.
type Terminator ¶ added in v0.3.0
type Terminator struct {
// contains filtered or unexported fields
}
Terminator is a component terminator that executes registered termination Hooks in a specified order.
func NewWithSignals ¶
NewWithSignals creates a new instance of component Terminator.
If the given appCtx parameter is canceled, the termination process will start for already registered Hook instances after calling Terminator.Wait method.
Example of useful signals might be: syscall.SIGINT, syscall.SIGTERM.
Note: this method will start internal monitoring goroutine.
Example ¶
package main import ( "context" "log" "syscall" "time" "github.com/skovtunenko/graterm" ) func main() { // create new Terminator instance: terminator, appCtx := graterm.NewWithSignals(context.Background(), syscall.SIGINT, syscall.SIGTERM) // register hooks... // Wire other components ... // Wait for os.Signal to occur, then terminate application with maximum timeout of 40 seconds: if err := terminator.Wait(appCtx, 40*time.Second); err != nil { log.Printf("graceful termination period was timed out: %+v", err) } }
Output:
func (*Terminator) SetLogger ¶ added in v0.3.0
func (t *Terminator) SetLogger(log Logger)
SetLogger sets the Logger implementation.
If log is nil, then NOOP logger implementation will be used.
Example ¶
package main import ( "context" "log" "syscall" "github.com/skovtunenko/graterm" ) func main() { // create new Terminator instance: terminator, _ := graterm.NewWithSignals(context.Background(), syscall.SIGINT, syscall.SIGTERM) // Set custom logger implementation instead of default NOOP one: terminator.SetLogger(log.Default()) }
Output:
func (*Terminator) Wait ¶ added in v0.3.0
Wait waits (with timeout) for Terminator to finish termination after the appCtx is done.
Example ¶
package main import ( "context" "log" "syscall" "time" "github.com/skovtunenko/graterm" ) func main() { // create new Terminator instance: terminator, appCtx := graterm.NewWithSignals(context.Background(), syscall.SIGINT, syscall.SIGTERM) // register hooks... // Wire other components ... // Wait for os.Signal to occur, then terminate application with maximum timeout of 40 seconds: if err := terminator.Wait(appCtx, 40*time.Second); err != nil { log.Printf("graceful termination period was timed out: %+v", err) } }
Output:
func (*Terminator) WithOrder ¶ added in v0.3.0
func (t *Terminator) WithOrder(order Order) *Hook
WithOrder sets the Order for the termination hook. It starts registration chain to register termination hook with priority.
The lower the Order the higher the execution priority, the earlier it will be executed. If there are multiple hooks with the same Order they will be executed in parallel.