grace

package
Version: v0.12.1 Latest Latest
Warning

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

Go to latest
Published: Jul 26, 2021 License: BSD-3-Clause, MIT, MIT-0, MIT Imports: 5 Imported by: 0

README

grace - start and gracefully shutdown processes

go get -u "tawesoft.co.uk/go"
import "tawesoft.co.uk/go/grace"
Links License Stable?
homedocssrc MIT candidate

About

Package grace implements a simple way to start multiple long-lived processes (e.g. goroutines) with cancellation, signal handling and graceful shutdown.

Examples

Start HTTP servers on multiple ports with graceful shutdown

package main

import (
    "context"
    "fmt"
    "net"
    "net/http"
    "os"
    "syscall"
    "time"

    "tawesoft.co.uk/go/grace"
)

// Implement grace.Process
type HttpServer struct {
    Addr string // e.g. ":8080"
    Srv *http.Server
    Ln net.Listener
}

func (s *HttpServer) Start(done func()) error {
    // non-async startup
    s.Srv = &http.Server{}
    ln, err := net.Listen("tcp", s.Addr)
    if err != nil { return err }
    s.Ln = ln

    // async server
    go func() {
        defer done()

        fmt.Printf("Serve %s\n", s.Addr)

        // blocks until Shutdown
        err := s.Srv.Serve(s.Ln)

        time.Sleep(50 * time.Millisecond)

        // ErrServerClosed on graceful close
        if err == http.ErrServerClosed {
            fmt.Printf("server closed normally\n")
        } else {
            fmt.Printf("server error: %v\n", err)
        }
    }()

    return nil
}

func (s *HttpServer) Stop(ctx context.Context) error {
    ctx, cancel := context.WithTimeout(ctx, time.Second * 1)
    defer cancel()
    fmt.Printf("Shutdown %s\n", s.Addr)
    return s.Srv.Shutdown(ctx) // closes s.Ln
}

func main() {
    servers := []grace.Process{
        &HttpServer{Addr: ":8081"},
        &HttpServer{Addr: ":8082"},
        &HttpServer{Addr: ":8083"},
        &HttpServer{Addr: ":8084"},
        // &HttpServer{Addr: ":8084"}, // uncomment this to try out startup errors
        &HttpServer{Addr: ":8085"},
    }

    signals := []os.Signal{
        syscall.SIGINT,
        syscall.SIGKILL,
        syscall.SIGTERM,
    }

    // blocks until cancelled, interrupted, terminated, or killed, until
    // all servers have shutdown, and all start functions have marked
    // themselves as completely `done()` (e.g. so they have time to clean up)
    signal, errs, err := grace.Run(context.Background(), servers, signals)

    if err != nil {
        fmt.Printf("Startup error: %v\n", err)
    } else {
        fmt.Printf("Shutdown complete. Recieved %s signal\n", signal)
    }

    if len(errs) > 0 {
        fmt.Printf("Shutdown errors: %v\n", errs)
    }
}

Getting Help

This package is part of tawesoft.co.uk/go, a monorepo for small Go modules maintained by Tawesoft®. Check out that URL for more information about other Go modules from Tawesoft plus community and commercial support options.

Documentation

Overview

Package grace implements a simple way to start multiple long-lived processes (e.g. goroutines) with cancellation, signal handling and graceful shutdown.

Examples

Start HTTP servers on multiple ports with graceful shutdown

https://www.tawesoft.co.uk/go/doc/grace/examples/multiportserver/

Package Information

License: MIT (see LICENSE.txt)

Stable: candidate

For more information, documentation, source code, examples, support, links, etc. please see https://www.tawesoft.co.uk/go and https://www.tawesoft.co.uk/go/grace

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Run

func Run(ctx context.Context, processes []Process, signals []os.Signal) (os.Signal, []error, error)

Run starts each process, waits for any signal in `notify` or until ctx is cancelled, then cancels each process. It blocks until all processes have been stopped with Stop() and all process Start() functions mark themselves as completely done().

The first return value is the os.Signal received.

The second return value is a list of errors for processes that returned errors when being cancelled.

The third return value returns any startup error.

The second return value may be non-empty even when the third return value is non-nil when there is both a startup error and an error stopping any previously started processes e.g. if process one starts but process two fails, then process one needs to be cancelled but may also run into an error cancelling.

Types

type Process

type Process interface {
	// Start launches a process. This shouldn't block, so launch goroutines or
	// other programs as necessary. Call done() when that goroutine returns
	// or that process has terminated. If Start returns an error, then done()
	// must not be called.
	Start(done func()) error

	// Stop stops a process. Derive from the context as necessary e.g.
	// use context.WithTimeout
	Stop(context.Context) error
}

Process defines a long-lived cancellable process

Source Files

Directories

Path Synopsis
examples
multiportserver
Start HTTP servers on multiple ports with graceful shutdown
Start HTTP servers on multiple ports with graceful shutdown

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
t or T : Toggle theme light dark auto
y or Y : Canonical URL