Documentation
¶
Overview ¶
Package lifecycle provides simple service management primitives.
A typical HTTP server could look like:
type MyHttpServer struct {
server http.Server
}
func NewHttpServer() *MyHttpServer {
mux := http.NewServeMux()
mux.HandleFunc("/", func(rw http.ResponseWriter, req *http.Request) {
rw.Write([]byte("Hello!"))
})
server := http.Server{Addr: ":8090", Handler: mux}
return &MyHttpServer{
server: server,
}
}
func (m *MyHttpServer) Start() error {
return m.server.ListenAndServe()
}
This is pretty simple code for simple projects, but lacks powerful state management. To add signal handling, graceful shutdown with automatic termination after a certain delay or readiness probes, one would need to write boulerplate code.
Using lifecycle, you can modify your code like:
type MyHttpServer struct {
*lifecycle.Worker
server http.Server
}
func NewHttpServer() *MyHttpServer {
mux := http.NewServeMux()
mux.HandleFunc("/", func(rw http.ResponseWriter, req *http.Request) {
rw.Write([]byte("Hello!"))
})
server := http.Server{Addr: ":8090", Handler: mux}
return &MyHttpServer{
Worker: lifecycle.NewWorker(&lifecycle.Hooks{
Start: lifecycle.DropContext(server.ListenAndServe),
Shutdown: server.Shutdown,
Terminate: lifecycle.DropContext(server.Close),
}),
server: server,
}
}
// No need to add Start, Stop and other lifecycle controlling methods,
// which are inherited from Worker.
Out of the box, this provides you with:
- Start, Stop and Terminate methods
- StartBackground, providing a non-blocking alternative
- Graceful termination timeout, terminating the service
- Error handling and filtering, for example to ignore http.ErrServerClosed
- Logging by providing your logger
- Readiness probes
- Observers to listen to the service state changes and errors
This package also provides a Host, which wraps multiple workers into a single startable unit exposing the same API.
Index ¶
- func IsInterrupted(err error) bool
- func IsInvalidState(err error) bool
- func Wait(duration time.Duration) func() <-chan error
- type Action
- type ContextHook
- type ErrorHook
- type Event
- type Hook
- type Hooks
- type Logger
- type Service
- type ServiceOptions
- type State
- type Worker
- func (c *Worker) Done() <-chan struct{}
- func (c *Worker) Name() string
- func (c *Worker) Observe(ch chan<- Event)
- func (c *Worker) Ready() <-chan struct{}
- func (c *Worker) Shutdown() error
- func (c *Worker) ShutdownCtx(ctx context.Context) error
- func (c *Worker) Start() error
- func (c *Worker) StartBackground() error
- func (c *Worker) StartBackgroundCtx(ctx context.Context) error
- func (c *Worker) StartCtx(ctx context.Context) error
- func (c *Worker) State() State
- func (c *Worker) Terminate() error
- func (c *Worker) TerminateCtx(ctx context.Context) error
- func (c *Worker) Unobserve(ch chan<- Event)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func IsInterrupted ¶
IsInterrupted returns true if the cause of the error is an interruption. This is for example returned by the service Start function when it is being shut down before the service is started.
func IsInvalidState ¶
IsInvalidState returns true if the cause of the error is an invalid initial state. This can be for example trying to start a stopped service, or stopping a stopped service.
Types ¶
type ContextHook ¶
ContextHook is a context-aware hook.
func DropContext ¶
func DropContext(hook Hook) ContextHook
DropContext is a helper function wrapping a context-naive hook as a context hook. The context provided to the resulting ContextHook is discarded.
type Event ¶
type Event struct {
// The context of the event, typically the one passed to the function from
// which the event originated.
Context context.Context
// The error that caused this status change, if any.
Error error
// The previous status of the service.
From State
// The new status of the service.
To State
}
Event is a struct passed to a service observers on a state change. It contains contextual information about the event.
type Hooks ¶
type Hooks struct {
// A friendly name for the service (optional)
Name string
// Start the service. This function is expected to block while the service
// is running. Returning from this function will cause the service to
// transition to Stopped if no error is returned or if the returned error is
// ignored by the Error hook. In other cases, the service will transition to
// an Error state.
Start ContextHook
// Gracefully shuts down the service. This function is expected to block
// until the service is shut down. Returning an error from this function
// will cause the service to transition to an Error state, unless the error
// is ignored by the Error hook. In this case, the server will remain in a
// ShuttingDown state until it is either terminated, or the Start hook
// returns.
Shutdown ContextHook
// Terminates the service. This function is expected to quickly terminate
// the service. The service will remain blocked until this function returns.
// Returning an error from this function will cause the service to
// transition to an Error state, unless the error is ignored by the Error
// hook. In this case, the server will remain in a Terminating state until
// it is either terminated, or the Start hook returns.
Terminate ContextHook
// Error receives error events. The event struct contains the context
// passed to the hook from which it occurred, as well as the error itself.
// The error returned by this function will be passed to the caller. If nil
// is returned, the error is ignored. This can be useful to suppress errors,
// for example http.ErrServerClosed when the service wraps an HTTP server.
Error ErrorHook
}
Hooks contain the functions called by the worker to control the underlying service.
type Logger ¶
type Logger interface {
// Logs an info message.
Info(msg string, keysAndValues ...interface{})
// Logs an error.
Error(err error, msg string, keysAndValues ...interface{})
}
Logger is a simple logger interface accepting key-value pair parameters.
type Service ¶
type Service interface {
// Name provides a user-friendly name for the service, that is used in
// the logs.
Name() string
// Starts the service. This function blocks until the service is
// stopped.
Start() error
// Starts the service providing context. This function blocks until the
// service is stopped.
StartCtx(ctx context.Context) error
// StartBackground starts the service in the background. This function does
// not block. It should typically be used in combination with Done.
StartBackground() error
// StartBackground starts the service in the background providing context.
// This function does not block. It should typically be used in combination
// with Done.
StartBackgroundCtx(ctx context.Context) error
// Shutdown shuts the service down gracefully.
Shutdown() error
// ShutdownCtx shuts the service down gracefully providing context.
ShutdownCtx(ctx context.Context) error
// Terminate forcefully terminates the service.
Terminate() error
// TerminateCtx forcefully terminates the service providing context.
TerminateCtx(ctx context.Context) error
// Ready returns a chan that is closed when the service is either started or
// has transitioned to an Error state.
Ready() <-chan struct{}
// Done returns a chan that is closed when the service is either stopped or
// has transitioned to an Error state.
Done() <-chan struct{}
// State returns the current state of the service.
State() State
// Observes registers a chan on which the service will post lifecycle events
// such as state changes and errors. No action is taken if ch is nil.
Observe(ch chan<- Event)
// Unobserve removes the provided chan from the list of observers. No action
// is taken if ch is nil or not in the list of observers.
Unobserve(ch chan<- Event)
}
Service represents a process that can be started, shut down or terminated. It exposes a set of methods to control the state of the service.
type ServiceOptions ¶
type ServiceOptions struct {
// ReadinessProbe allows to specify how the service transitions from a
// Starting to a Started state. If provided, the service will wait for the
// chan returned by this function to either be closed, or to return
// an error. In the latter case, the service will transition to an Error
// state, unless the error is ignored by the Error hook.
ReadinessProbe func() <-chan error
// ShutdownTimeout defines a maximum amount of time for which the service
// can remain in ShuttingDown state. When the specified amount of time
// is elapsed, the service is terminated (default: 15 seconds).
ShutdownTimeout time.Duration
// Signals defines the signals to listen to. When one of these signals is
// received, the action defined by SignalAction will be taken (default:
// syscall.SIGINT, syscall.SIGTERM).
Signals []os.Signal
// Defines the action to be taken when a signal is received (default:
// Shutdown)
SignalAction Action
// Sets the Logger to use to log worker events. If nil, the logging messages
// are discarded.
Logger Logger
}
ServiceOptions contains options for the service.
type State ¶
type State uint8
State represents a state in the lifecycle state machine. The state machine provided by this package is the following:
+--------------+
| Initial |
+-+------------+
|
+-v------------+
+----+ Starting +----+
| +-+------------+ |
| | |
| +-v------------+ |
+----+ Started +----+
| +-+------------+ |
| | |
| +-v------------+ |
+----+ ShuttingDown +----+
| +-+------------+ |
| | |
| +-v------------+ +-v------------+
+----+ Stopped <--+ Terminating |
| +--------------+ +-+------------+
| |
| +--------------+ |
+----> Error <----+
+--------------+
const ( // Initial state of a service Initial State = iota // Starting represents a system that is in the process of starting. Starting // Started represents a running service. Started // ShuttingDown represents a process being shut down gracefully. ShuttingDown // Terminating represents a process being forcefully terminated. Terminating // Stopped represents a service shut down without errors. Stopped // Error represents a service having reached an error. Error )
type Worker ¶
type Worker struct {
// contains filtered or unexported fields
}
Worker is a Service that can be started, stopped and terminated based on a set of provided hooks.
func NewWorker ¶
NewWorker creates a Worker with the provided hooks. It returns nil if either of the hook structure, the start hook or the shutdown hook is nil.
func NewWorkerWithOptions ¶
func NewWorkerWithOptions(hooks *Hooks, opts *ServiceOptions) *Worker
NewWorkerWithOptions creates a Worker with the provided hooks and options It returns nil if either of the hook structure, the start hook or the shutdown hook is nil.
func (*Worker) Done ¶
func (c *Worker) Done() <-chan struct{}
Done returns a chan that is closed when the service is either stopped or has transitioned to an Error state.
func (*Worker) Observe ¶
Observe registers a chan on which the service will post lifecycle events such as state changes and errors. No action is taken if ch is nil.
func (*Worker) Ready ¶
func (c *Worker) Ready() <-chan struct{}
Ready returns a chan that is closed when the service is either started or has transitioned to an Error state.
func (*Worker) Shutdown ¶
Shutdown shuts the service down gracefully. This function returns a non-nil error if the Shutdown hook returns an error, unless the error is ignored by the Error hook.
func (*Worker) ShutdownCtx ¶
ShutdownCtx shuts the service down gracefully providing context. This function returns a non-nil error if the Shutdown hook returns an error, unless the error is ignored by the Error hook.
func (*Worker) Start ¶
Start the service. This function blocks until the service is stopped. This function returns a non-nil error if either the start hook or the readiness probe return an error, unless the error is ignored by the Error hook.
func (*Worker) StartBackground ¶
StartBackground starts the service in the background. This function does not block. It should typically be used in combination with Done. This function returns a non-nil error if either the start hook or the readiness probe return an error, unless the error is ignored by the Error hook.
func (*Worker) StartBackgroundCtx ¶
StartBackgroundCtx starts the service in the background providing background. This function does not block. It should typically be used in combination with Done. This function returns a non-nil error if either the start hook or the readiness probe return an error, unless the error is ignored by the Error hook.
func (*Worker) StartCtx ¶
StartCtx starts the service providing context. This function blocks until the service is stopped. This function returns a non-nil error if either the start hook or the readiness probe return an error, unless the error is ignored by the Error hook.
func (*Worker) Terminate ¶
Terminate forcefully terminates the service. This function returns a non-nil error if the Shutdown hook returns an error, unless the error is ignored by the Error hook.
func (*Worker) TerminateCtx ¶
TerminateCtx forcefully terminates the service providing context. This function returns a non-nil error if the Shutdown hook returns an error, unless the error is ignored by the Error hook.