Documentation ¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrStop = errors.New("service stopped")
ErrStop is an error injected into WithCancelCause when context is canceled because a service is stopping. Makes it possible to differentiate a controlled stop from a context cancellation.
Functions ¶
func StartStopFunc ¶ added in v0.1.0
func StartStopFunc(startFunc func(ctx context.Context, shouldStart bool, stopped chan struct{}) error) *startStopFunc
StartStopFunc produces a `startstop.Service` from a function. It's useful for very small services that don't necessarily need a whole struct defined for them.
func StopAllParallel ¶ added in v0.1.0
func StopAllParallel(services []Service)
StopAllParallel stops all the given services in parallel and waits until they've all stopped successfully.
Types ¶
type BaseStartStop ¶
type BaseStartStop struct {
// contains filtered or unexported fields
}
BaseStartStop is a helper that can be embedded on a queue maintenance service and which will provide the basic necessities to safely implement the Service interface in a way that's not racy and can tolerate a number of edge cases. It's packaged separately so that it doesn't leak its internal variables into services that use it.
Services should implement their own Start function which invokes StartInit first thing, return if told not to start, spawn a goroutine with their main run block otherwise, and make sure to defer a close on the stop channel returned by StartInit within that goroutine.
A Stop implementation is provided automatically and it's not necessary to override it.
func (*BaseStartStop) StartInit ¶
StartInit should be invoked at the beginning of a service's Start function. It returns a context for the service to use, a boolean indicating whether it should start (which will be false if the service is already started), and a stopped channel. Services should defer a close on the stop channel in their main run loop.
func (s *Service) Start(ctx context.Context) error { ctx, shouldStart, stopped := s.StartInit(ctx) if !shouldStart { return nil } go func() { defer close(stopped) <-ctx.Done() ... }() return nil }
Be careful to also close it in the event of startup errors, otherwise a service that failed to start once will never be able to start up.
ctx, shouldStart, stopped := s.StartInit(ctx) if !shouldStart { return nil } if err := possibleStartUpError(); err != nil { close(stopped) return err } ...
func (*BaseStartStop) Stop ¶
func (s *BaseStartStop) Stop()
Stop is an automatically provided implementation for the maintenance Service interface's Stop.
func (*BaseStartStop) StopInit ¶ added in v0.1.0
func (s *BaseStartStop) StopInit() (bool, <-chan struct{}, func(didStop bool))
StopInit provides a way to build a more customized Stop implementation. It should be avoided unless there'a an exceptional reason not to because Stop should be fine in the vast majority of situations.
It returns a boolean indicating whether the service should do any additional work to stop (false is returned if the service was never started), a stopped channel to wait on for full stop, and a finalizeStop function that should be deferred in the stop function to ensure that locks are cleaned up and the struct is reset after stopping.
func (s *Service) Stop(ctx context.Context) error { shouldStop, stopped, finalizeStop := s.StopInit(ctx) if !shouldStop { return } defer finalizeStop(true) ... }
finalizeStop takes a boolean which indicates where the service should indeed be considered stopped. This should usually be true, but callers can pass false to cancel the stop action, keeping the service from starting again, and potentially allowing the service to try another stop.
func (*BaseStartStop) Stopped ¶
func (s *BaseStartStop) Stopped() <-chan struct{}
Stopped returns a channel that can be waited on for the service to be stopped. This function is only safe to invoke after successfully waiting on a service's Start, and a reference to it must be taken _before_ invoking Stop.
type Service ¶ added in v0.1.0
type Service interface { // Start starts a service. Services are responsible for backgrounding // themselves, so this function should be invoked synchronously. Services // may return an error if they have trouble starting up, so the caller // should wait and respond to the error if necessary. Start(ctx context.Context) error // Stop stops a service. Services are responsible for making sure their stop // is complete before returning so a caller can wait on this invocation // synchronously and be guaranteed the service is fully stopped. Services // are expected to be able to tolerate (1) being stopped without having been // started, and (2) being double-stopped. Stop() }
Service is a generalized interface for a service that starts and stops, usually one backed by embedding BaseStartStop.