lameduck

package module
v0.5.3 Latest Latest
Warning

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

Go to latest
Published: Aug 5, 2021 License: MIT Imports: 10 Imported by: 0

README

toolman.org/net/lameduck

Package lameduck provides coordinated lame-duck behavior for any service implementing this package's Server interface.

type Server interface {
  Serve(context.Context) error
  Shutdown(context.Context) error
  Close() error
}

By default, lame-duck mode is triggered by receipt of SIGINT or SIGTERM and the default lame-duck period is 3 seconds. Options are provided to alter these (and other) values.

This package is written assuming behavior similar to the standard library's http.Server -- in that its Shutdown and Close methods exhibit behavior matching the lameduck.Server interface -- however, in order to allow other types to be used, a Serve method that returns nil is also needed.

Here's an example wrapper around http.Server that leverages this package:

package mypkg

import (
  "net/http"
  "toolman.org/net/lameduck"
)

type MyLameDuckServer struct {
   // This embedded http.Server provides Shutdown and Close methods
   // with behavior expected by the lameduck.Server interface.
  *http.Server
}

// Serve executes the embedded http.Server's ListenAndServe method in
// a manner compliant with the lameduck package's Server interface.
func (s *MyLameDuckServer) Serve(context.Contxt) error {
  err := s.ListenAndServe()

  if err == http.ErrServerClosed {
    err = nil
  }

  return err
}

// Run will run the receiver's embedded http.Server and provide
// lame-duck coverage on receipt of SIGTERM or SIGINT.
func (s *MyLameDuckServer) Run(ctx context.Context) error {
  return lameduck.Run(ctx, s)
}

...and a simple main packages that uses it:

package main

import (
  "fmt"
  "net/http"

  "mypkg"
)

func main() {
  mlds := &mypkg.MyLameDuckServer{&http.Server{Addr: ":8080"}}

  if err := mlds.Run(context.Background()); err != nil {
    fmt.Printf("Server error: %v", err)
  }
}

The above illustrates a simple wrapper around http.Server that may be started using the provided Run method. This server will continue to run until receiving a SIGINT or SIGTERM. On receipt of one of these signals, lameduck logic will call its Server's Shutdown method which, in turn, will cause ListenAndServe to return immediately -- as specified in the net/http documentation:

When Shutdown is called, Serve, ListenAndServe, and ListenAndServeTLS immediately return ErrServerClosed. Make sure the program doesn't exit and waits instead for Shutdown to return.

Note however that the call to the underlying Server's Shutdown method indicates that start of lame-duck processing which will continue until all in-flight requests have completed or the provided Context is canceled:

Shutdown gracefully shuts down the server without interrupting any active connections. Shutdown works by first closing all open listeners, then closing all idle connections, and then waiting indefinitely for connections to return to idle and then shut down. If the provided context expires before the shutdown is complete, Shutdown returns the context's error, otherwise it returns any error returned from closing the Server's underlying Listener(s).

This package ensures that a proper Context is provided to Shutdown having a Deadline indicating the desired lame-duck grace period -- by default, 3 seconds -- then reacts accordingly based on the error returned by Shutdown.

If a non-nil error is returned from Run it will always be of type LameDuckError:

type LameDuckError struct {
  Expired bool
  Failed  bool
  Err     error
}

If Serve returns an error, Run returns a *LameDuckError with Failed set to true and Err set to that returned by Serve.

If the call to Shutdown returns nil, this indicates the the underlying Server has stopped completely within the desired lame-duck grace period. In this case, Run will return nil. Otherwise, the error returned by Shutdown will follow the below rules:

  • If Shutdown returns context.DeadlineExceeded then Run's *LameDuckError will have a true value for Expired and its Err field will contain the error returned from the Server's Close method - if any. Note also that the underlying Server's Close method is only called when Shutdown returns context.DeadlineExceeded.

  • On the other hand, if Shutdown returns some other error, Run will return a *LameDuckError wrapping that error but both of its boolean fields will be false.

Documentation

Overview

Package lameduck provides coordinated lame-duck behavior for any service implementing this package's Server interface.

By default, lame-duck mode is triggered by receipt of SIGINT or SIGTERM and the default lame-duck period is 3 seconds. Options are provided to alter these (an other) values.

This package is written assuming behavior similar to the standard library's http.Server -- in that its Shutdown and Close methods exhibit behavior matching the lameduck.Server interface -- however, in order to allow other types to be used, a Serve method that returns nil is also needed.

type LameDuckServer struct {
	 // This embedded http.Server provides Shutdown and Close methods
	 // with behavior expected by the lameduck.Server interface.
  *http.Server
}

// Serve executes ListenAndServe in a manner compliant with the
// lameduck.Server interface.
func (s *LameDuckServer) Serve(context.Contxt) error {
  err := s.Server.ListenAndServe()

  if err == http.ErrServerClosed {
    err = nil
  }

  return err
}

// Run will run the receiver's embedded http.Server and provide
// lame-duck coverage on receipt of SIGTERM or SIGINT.
func (s *LameDuckServer) Run(ctx context.Context) error {
  return lameduck.Run(ctx, s)
}

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Run

func Run(ctx context.Context, svr Server, options ...Option) error

Run executes the given Server providing coordinated lame-duck behavior on receipt of one or more configurable signals. By default, the lame-duck period is 3s and is triggered by SIGINT or SIGTERM. Options are available to alter these values.

Note that:

r, err := lameduck.Run(ctx, svr)

...is equivalent to calling:

if r, err := lameduck.NewRunner(svr); err == nil {
	r.Run(ctx)
}

Types

type LameDuckError

type LameDuckError struct {
	Expired bool
	Failed  bool
	Err     error
}

LameDuckError is the error type returned by Run for errors related to lame-duck mode.

func (*LameDuckError) Error

func (lde *LameDuckError) Error() string

func (*LameDuckError) Unwrap

func (lde *LameDuckError) Unwrap() error

type Logger

type Logger interface {
	Infof(string, ...interface{})
}

Logger is the interface needed for the WithLogger Option.

type Option

type Option interface {
	// contains filtered or unexported methods
}

Option is the interface implemented by types that offer optional behavior while running a Server with lame-duck support.

func Period

func Period(p time.Duration) Option

Period returns an Option that alters the lame-duck period to the given Duration.

func Signals

func Signals(s ...os.Signal) Option

Signals returns an Options that changes the list of Signals that trigger the beginning of lame-duck mode. Using this Option fully replaces the previous list of triggering signals.

func WithLogger

func WithLogger(l Logger) Option

WithLogger returns an Option that alters this package's logging facility to the provided Logger. Note, the default Logger is one derived from 'github.com/golang/glog'. To prevent all logging, use WithoutLogger.

func WithoutLogger

func WithoutLogger() Option

WithoutLogger returns an option the disables all logging from this package.

type Runner added in v0.5.3

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

Runner is the lame-duck coordinator for a type implementing the Server interface.

func NewRunner added in v0.5.3

func NewRunner(svr Server, options ...Option) (*Runner, error)

NewRunner returns a lame-duck Runner that providing coordinated lame-duck behavior for the given svr.

See the Run func for details.

func (*Runner) Ready added in v0.5.3

func (r *Runner) Ready() <-chan struct{}

Ready returns a channel that is closed when the receiver's underlying Server is ready to serve reqeuests.

func (*Runner) Run added in v0.5.3

func (r *Runner) Run(ctx context.Context) error

Run executes the receiver's Server while providing coordinated lame-duck behavior on receipt of one or more configurable signals.

See the Run func for details.

func (*Runner) State added in v0.5.3

func (r *Runner) State() State

State returns the current runtime State for the receiver.

type Server

type Server interface {
	// Serve executes the Server. If Serve returns an error, that error will be
	// returned immediately by Run and no lame-duck coverage will be provided.
	//
	Serve(context.Context) error

	// Shutdown is called by Run (after catching one of the configured signals)
	// to initiate a graceful shutdown of the Server; this marks the beginning
	// of lame-duck mode. If Shutdown returns a nil error before the configured
	// lame-duck period has elapsed, Run will immediately return nil as well.
	//
	// The Context provided to Shutdown will have a timeout set to the configured
	// lame-duck Period. If Shutdown returns context.DeadlineExceeded, Run will
	// return a LameDuckError with its Expired field set to true and Err set to
	// the return value from calling Close.
	//
	// Any other error returned by Shutdown will be wrapped by a LameDuckError
	// with its Expired field set to false.
	Shutdown(context.Context) error

	// Close is called by Run when Shutdown returns context.DeadlineExceeded and
	// its return value will be assigned to the Err field of the LameDuckError
	// returned by Run.
	Close() error
}

Server defines the interface that should be implemented by types intended for lame-duck support. It is expected that these methods exhibit behavior similar to http.Server -- in that a call to Shutdown or Close should cause Serve to return immediately.

However, unlike http.Server's Serve, ListenAndServe, and ListenAndServeTLS methods (which return http.ErrServerClosed in this situation), this Serve method should return a nil error when lame-duck mode is desired.

type State added in v0.5.3

type State int

State represents the lame-duck runtime state for a Server.

const (
	Unknown    State = iota // Zero value; state is unknown
	NotStarted              // The Server has not been started
	Running                 // The Server is currently running without incident
	Failed                  // The Server failed to start
	Stopping                // The Server is in the process of stopping
	Stopped                 // The Server has been stopped.
)

func (State) String added in v0.5.3

func (s State) String() string

Jump to

Keyboard shortcuts

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