guillotine

package module
v0.1.3 Latest Latest
Warning

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

Go to latest
Published: Sep 24, 2019 License: MIT Imports: 9 Imported by: 0

README

guillotine

Terminating systems with multiple components, in style.

Tag Drone Go Report Card GoDoc

Usage

guillotine is a package for shutting down complex, multi-component systems.

It defines a Finalizer, which is a function that should be run during program termination.

type Finalizer func() error

Finalizers should be added to the Guillotine in your main function, after resources are initialized. After all Finalizers are added, you should start long-running processes like HTTP servers on separate goroutines; call guillotine.Trigger after these processes exit, in case they exit early due to a startup failure.

package main

import (
	"context"
	"fmt"
	"io"
	"net/http"
	"os"

	"github.com/cockroachdb/errors"
	"go.stevenxie.me/guillotine"
)

func main() {
	// Create a guillotine, configure it to trigger when receiving a termination
	// signal from the OS.
	guillo := guillotine.New()
	guillo.TriggerOnTerminate()

	// Execute the guillotine before main finishes.
	defer func() {
		if ok, errs := guillo.Execute(); !ok {
			for _, err := range errs {
				fmt.Fprintf(os.Stderr, "A finalizer failed: %v\n", err)
			}
			os.Exit(1)
		}
	}()

	// Initialize resources, like files or databases.
	file, err := os.Open("resource.txt")
	if err != nil {
		panic(err)
	}
	guillo.AddCloser(file, guillotine.WithPrefix("closing file"))

	// Start long-running processes, like servers.
	//
	// We add the server itself as a finalizer so it can be shut down in response
	// to some other shutdown signal, like an interrupt / termination signal.
	const port = 8080
	srv := &http.Server{
		Addr: fmt.Sprintf(":%d", port),
		Handler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
			if _, err := io.Copy(w, file); err != nil {
				panic(err)
			}
		}),
	}
	guillo.AddFinalizer(
		func() error { return srv.Shutdown(context.Background()) },
		guillotine.WithPrefix("shutting down server"),
	)

	// Blocks thread while server runs; stops either when the Guillotine
	// shuts down the server, or the server fails to start up.
	fmt.Printf("Listening on port %d...\n", port)
	if err = srv.ListenAndServe(); err != nil {
		if !errors.Is(err, http.ErrServerClosed) {
			fmt.Fprintf(os.Stderr, "Error while starting server: %v\n", err)
			guillo.Execute()
			os.Exit(2)
		}
	}
}

See the full example for more details.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Callback

type Callback func(error) error

A Callback is called when a Guillotine runs a Finalizer.

It is used as a way to perform other actions after a Finalizer is run, and to modify the error returned by the Finalizer.

func WithEffect added in v0.1.1

func WithEffect(f func(error)) Callback

WithEffect creates a Callback that runs a function that receives the error created by the Finalizer, and returns nothing.

It is intended for functions with side effects involving the error, like logging functions, etc.

func WithError

func WithError(msg string) Callback

WithError creates a Callback that creates an Error if the Finalizer didn't return one.

func WithErrorf

func WithErrorf(format string, args ...zero.Interface) Callback

WithErrorf is like WithError, but creates a formatted error message.

func WithFunc added in v0.1.1

func WithFunc(f func()) Callback

WithFunc creates a Callback that runs an arbitrary function.

func WithPrefix

func WithPrefix(msg string) Callback

WithPrefix creates a Callback adds a prefix to the error from a Finalizer.

type Config

type Config struct {
	Logger logrus.FieldLogger
}

A Config configures a Guillotine.

type Finalizer

type Finalizer func() error

A Finalizer is a function that returns an error.

type Guillotine

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

A Guillotine is used to shut down a system consisting of multiple components.

func New

func New(opts ...Option) *Guillotine

New creates a new Guillotine.

func (*Guillotine) AddCloser

func (g *Guillotine) AddCloser(closer io.Closer, cb ...Callback)

AddCloser adds an io.Closer to the Guillotine.

func (*Guillotine) AddFinalizer

func (g *Guillotine) AddFinalizer(f Finalizer, cb ...Callback)

AddFinalizer adds a Finalizer to the Guillotine.

func (*Guillotine) AddFunc

func (g *Guillotine) AddFunc(f func(), cb ...Callback)

AddFunc adds a regular function to the Guillotine.

func (*Guillotine) Execute

func (g *Guillotine) Execute() (ok bool, errs []error)

Execute runs each Finalizer in reverse order.

It returns a boolean (ok) that is true if all Finalizers ran without errors, and the slice of all the Finalizer errors that occurred during execution.

func (*Guillotine) Trigger

func (g *Guillotine) Trigger()

Trigger triggers an asynchronous execution process which will run each Finalizer in reverse order.

Use g.Wait to wait for the execution process to complete.

func (*Guillotine) TriggerOnSignal

func (g *Guillotine) TriggerOnSignal(sig ...os.Signal)

TriggerOnSignal waits for a signal before triggering an execution (see g.Terminate).

func (*Guillotine) TriggerOnTerminate

func (g *Guillotine) TriggerOnTerminate()

TriggerOnTerminate waits for a termination signal (syscall.SIGTERM, syscall.SIGINT) before triggering an exeuction (see g.Terminate).

func (*Guillotine) Wait

func (g *Guillotine) Wait() []error

Wait blocks until the Guillotine completes its asynchronous execution process, and returns the resulting errors from its finalizers.

type Option

type Option func(*Config)

An Option modifies a Config.

func WithLogger

func WithLogger(log logrus.FieldLogger) Option

WithLogger configures a Guillotine to write logs with log.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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