safedown

package module
v1.4.0 Latest Latest
Warning

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

Go to latest
Published: Aug 22, 2023 License: MIT Imports: 3 Imported by: 0

README

Safedown

Safedown is for ensuring that an application shuts down gracefully even when termination or interruption signals are received.

Adding shutdown actions along with a set of signals allows for methods (in this case cancel) to be run when a termination signal, or similar, is received.

package main

import (
	"context"
	"syscall"
	"time"

	"github.com/Graphmasters/safedown"
)

func main() {
    defer println("Finished")
    
    // The shutdown actions are initialised and will only run
    // if one of the provided signals is received.
    sa := safedown.NewShutdownActions(safedown.FirstInLastDone, syscall.SIGTERM, syscall.SIGINT)

    // The context can be cancelled be either through the 
    // shutdown actions or via the defer.
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()
    sa.AddActions(cancel)

    println("Processing is starting")
    t := time.After(10 * time.Second)
    select {
    case <-ctx.Done():
    case <-t:
    }
}

To ensure that the shutdown logic (represented by actions) always runs (particularly for running unending applications) one can also include the line defer sa.Shutdown().

package main

import (
	"context"
	"syscall"
	"time"

	"github.com/Graphmasters/safedown"
)

func main() {
    defer println("Finished")

    // The shutdown actions are initialised and Shutdown is
    // deferred. This ensures that the shutdown actions are
    // always run and that the main is blocked from 
    // finishing until the shutdown process is complete.
    sa := safedown.NewShutdownActions(safedown.FirstInLastDone, syscall.SIGTERM, syscall.SIGINT)
    defer sa.Shutdown()

    // The context can be cancelled be through the shutdown
    // action, triggered either by a signal or sa.Shutdown().
    ctx, cancel := context.WithCancel(context.Background())
    sa.AddActions(cancel)

    println("Processing is starting")
    t := time.After(10 * time.Second)
    select {
    case <-ctx.Done():
    case <-t:
    }
}

One can also manage shutdown actions across goroutines by creating the shutdown actions without any signals to be listened for.

Additional examples can be found in the examples module

  1. HTTP server with database.
F.A.Q.
  • How do I ensure that the shutdown actions complete before the program terminates? Use either Shutdown() or Wait(). We recommend against using Wait() as it is possible the shutdown actions will never be triggered and the program will never stop.

Documentation

Overview

Package safedown provides a graceful way to shutdown an application even when an interrupt signal is received.

Example (WithShutDown)

Example_withShutDown demonstrates how to use the Shutdown method can be used.

package main

import (
	"fmt"
	"os"

	"github.com/Graphmasters/safedown"
)

func main() {
	// Creates the shutdown actions and defers the Shutdown method.
	sa := safedown.NewShutdownActions(safedown.FirstInLastDone)
	defer sa.Shutdown()

	// Sets the function to be called if a signal is received
	sa.SetOnSignal(func(signal os.Signal) {
		fmt.Printf("A signal was received: %s\n", signal.String())
	})

	// The first action added will be the last done
	sa.AddActions(func() {
		fmt.Println("... and this will be done last.")
	})

	// The last action added will be the first done
	sa.AddActions(func() {
		fmt.Println("This will be done first ...")
	})

}
Output:

This will be done first ...
... and this will be done last.
Example (WithSignalReceived)

Example_withSignalReceived demonstrates how setting up the safedown's shutdown actions works when a signal is received.

package main

import (
	"context"
	"fmt"
	"os"
	"syscall"
	"time"

	"github.com/Graphmasters/safedown"
)

func main() {
	// This code sends a termination signal being sent. This is here purely
	// to demonstrate functionality and should not be included in any production
	// code.
	go func(pid int) {
		time.Sleep(time.Second)
		process := os.Process{Pid: pid}
		if err := process.Signal(syscall.SIGTERM); err != nil {
			fmt.Printf("error sending signal: %s", err)
		}
	}(os.Getpid())

	defer fmt.Println("Finished")

	// The shutdown actions are initialised and will only run
	// if one of the provided signals is received.
	sa := safedown.NewShutdownActions(safedown.FirstInLastDone, syscall.SIGTERM, syscall.SIGINT)

	// Sets the function to be called if a signal is received
	sa.SetOnSignal(func(signal os.Signal) {
		fmt.Printf("Signal received: %s\n", signal.String())
	})

	// The context can be cancelled be either through the
	// shutdown actions or via the defer.
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	sa.AddActions(cancel)

	fmt.Println("Processing starting")
	t := time.After(2 * time.Second)
	select {
	case <-ctx.Done():
		fmt.Println("Context cancelled")
	case <-t:
		fmt.Println("Ticker ticked")
	}

}
Output:

Processing starting
Signal received: terminated
Context cancelled
Finished
Example (WithoutSignalReceived)

Example_withoutSignalReceived demonstrates how setting up the safedown's shutdown actions works when no signal is received (and the program can terminate of its own accord).

package main

import (
	"context"
	"fmt"
	"os"
	"syscall"
	"time"

	"github.com/Graphmasters/safedown"
)

func main() {
	defer fmt.Println("Finished")

	// The shutdown actions are initialised and will only run
	// if one of the provided signals is received.
	sa := safedown.NewShutdownActions(safedown.FirstInLastDone, syscall.SIGTERM, syscall.SIGINT)

	// Sets the function to be called if a signal is received
	sa.SetOnSignal(func(signal os.Signal) {
		fmt.Printf("Signal received: %s\n", signal.String())
	})

	// The context can be cancelled be either through the
	// shutdown actions or via the defer.
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	sa.AddActions(cancel)

	fmt.Println("Processing starting")
	t := time.After(2 * time.Second)
	select {
	case <-ctx.Done():
		fmt.Println("Context cancelled")
	case <-t:
		fmt.Println("Ticker ticked")
	}

}
Output:

Processing starting
Ticker ticked
Finished

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Order

type Order int

Order represents the order that the shutdown actions will be executed.

const (
	FirstInFirstDone Order = iota // Actions are executed in the order they are added.
	FirstInLastDone               // Actions are executed in the reversed order they are added.
	Parallel                      // Each action is run in a separate go routine
)

type ShutdownActions

type ShutdownActions struct {
	// contains filtered or unexported fields
}

ShutdownActions contains actions that are run when the os receives an interrupt signal. This object must be created using the NewShutdownActions function.

func NewShutdownActions

func NewShutdownActions(order Order, signals ...os.Signal) *ShutdownActions

NewShutdownActions creates and initialises a new set of shutdown actions. The actions (added later) will be executed if any of the signals provided are received. The order determines the order the actions will be executed.

func (*ShutdownActions) AddActions

func (sa *ShutdownActions) AddActions(actions ...func())

AddActions adds actions to be run on shutdown or when a signal is received. Any action added after a signal has been received or the Shutdown method has been called will not be executed.

func (*ShutdownActions) SetOnSignal

func (sa *ShutdownActions) SetOnSignal(onSignal func(os.Signal))

SetOnSignal sets the method which will be called if a signal is received.

func (*ShutdownActions) Shutdown

func (sa *ShutdownActions) Shutdown()

Shutdown runs the shutdown actions and stops listening for signals (if doing so). This method blocks until all shutdown actions have been run, regardless of if they have been triggered by receiving a signal or calling this method.

func (*ShutdownActions) Wait

func (sa *ShutdownActions) Wait()

Wait waits until all the shutdown actions have been called.

Jump to

Keyboard shortcuts

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