Documentation
¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ( ErrServiceIsNil = errors.New("service is nil") ErrNoService = errors.New("no service specified") ErrNoServiceStart = errors.New("no service start order specified") ErrNoServiceStop = errors.New("no service stop order specified") ErrServicesStartStopMismatch = errors.New("services to start and stop mismatch") ErrServicesNotUnique = errors.New("services are not unique") ErrAlreadyStarted = errors.New("already started") ErrAlreadyStopped = errors.New("already stopped") )
Functions ¶
This section is empty.
Types ¶
type Group ¶
type Group struct {
// contains filtered or unexported fields
}
Group is a group of services to start and stop in parallel. It implements the Service interface itself.
func NewGroup ¶
func NewGroup(settings GroupSettings) (group *Group, err error)
NewGroup creates a new group of services given the settings, and returns an error if any setting is not valid.
func (*Group) Start ¶
Start starts services specified in parallel.
If a service fails to start, the `startErr` is returned and all other running services are stopped.
If a service fails after `Start` returns without error, all other running services are stopped and the error is sent in the `runError` channel which is then closed. A caller should listen on `runError` until the `Stop` method call fully completes, since a run error can theoretically happen at the same time the caller calls `Stop` on the group.
If the group is already running, the `ErrAlreadyStarted` error is returned.
If the context is canceled, all the starting operations are canceled, all already running services are stopped and the context error is wrapped in the `startErr` returned.
func (*Group) Stop ¶
Stop stops running services of the group in parallel. If an error occurs for any of the service stop, the other running services will still be stopped. Only the first non nil service stop error encountered is returned, but the hooks can be used to process each error returned. If the group is already stopped, the `ErrAlreadyStopped` error is returned.
type GroupSettings ¶
type GroupSettings struct {
// Name is the sequence name, used for hooks and errors.
Name string
// Services specifies the services to start and stop in parallel.
// Note their order does not matter.
Services []Service
// Hooks are hooks to call when starting and stopping
// each service. Hooks method calls should be thread safe
// since its methods are called in parallel goroutines.
// It defaults to a no-op hooks implementation if left unset.
Hooks Hooks
}
GroupSettings contains settings for a group of services.
type Hooks ¶
type Hooks interface {
HooksStart
HooksStop
HooksCrash
}
HooksStart is the interface required to hook into service events.
type HooksCrash ¶
HooksCrash is the interface required to hook into service crash events.
type HooksStart ¶
HooksStart is the interface required to hook into service start and started events.
type Restarter ¶
type Restarter struct {
// contains filtered or unexported fields
}
Restarter implements a service which restarts an underlying service if it crashes. The restarter only crashes if the underlying services fails to start on a subsequent run.
func NewRestarter ¶
func NewRestarter(settings RestarterSettings) (restarter *Restarter, err error)
NewRestarter creates a new restarter given the settings. It returns an error if any of the settings is not valid.
func (*Restarter) Start ¶
Start starts the underlying service.
If the underlying service fails to start, the `startErr` is returned.
If the underlying service fails after this method call returns without error, it is automatically restarted and no error is emitted in the `runError` channel.
If a subsequent service start fails, the start error is sent in the `runError` channel, this channel is closed and the restarter stops. A caller should listen on `runError` until the `Stop` method call fully completes, since a run error can theoretically happen at the same time the caller calls `Stop` on the restarter.
If the restarter is already running, the `ErrAlreadyStarted` error is returned.
If the context is canceled, the service starting operation is canceled, and the context error is wrapped in the `startErr` returned.
func (*Restarter) Stop ¶
Stop stops the underlying service and the internal run error restart-watcher goroutine. If the restarter is already stopped, the `ErrAlreadyStopped` error is returned. Note if the restarter is currently restarting the underlying service, it has to finish the start before the stopping can start.
type RestarterSettings ¶
type RestarterSettings struct {
// Service is the service to restart.
// It must be set for settings validation to succeed.
Service Service
// Hooks are hooks to call when the service starts,
// stops or crashes. It defaults to a noop hooks
// implementation.
Hooks Hooks
}
RestarterSettings contains settings for a restarter.
type RunFunction ¶
RunFunction is a functional type to simplify a service implementation together with `NewRunWrapper`.
- `ctx` must be listened on to trigger a stop. Note the `stopError` must be written to when stopping.
- `ready` must be closed as soon as the run function has started successfully. Often a simple `close(ready)` at the start of the run body code is enough.
- `runError` must have a non-nil error written to it if the run function fails unexpectedly, and the function must promptly `return` right after writing the error. If the function is stopped, the `runError` channel should not be written to nor closed. Alternatively, if a run error is written to this channel, the `stopError` channel should not be written to nor closed. If an error occurs before the run function is ready, the `ready` channel must not be closed. The `runError` channel should be closed after writing an error to it to prevent further writes. Note if an error is written to this channel, the run wrapper service will be considered as crashed.
- `stopError` must have an error written to it when the context gets canceled, to signal the stopping result. In the case of no stopping error, the channel must be closed. Otherwise, the error must be written to the channel and the channel should then be closed to prevent further writes. The run function must `return` right after.
A very simple run function template would be:
func run(ctx context.Context, ready chan<- struct{},
runError, stopError chan<- error) {
close(ready)
select {
case <-ctx.Done():
// cleanup
close(stopError) // successful stop
return
case err := <-someChannel:
if err != nil {
runError <- err
close(runError)
return
}
}
}
type RunWrapper ¶
type RunWrapper struct {
// contains filtered or unexported fields
}
RunWrapper is a service implementation taking care of the many edge cases and race conditions that can occur when running a service, and uses a user-injected `RunFunction` to run the service.
func NewRunWrapper ¶
func NewRunWrapper(name string, run RunFunction) *RunWrapper
NewRunWrapper creates a new service wrapper using the service name and run function given.
func (*RunWrapper) Start ¶
func (w *RunWrapper) Start(startCtx context.Context) (runError <-chan error, startErr error)
Start starts the service and is thread safe. It returns a `runError` channel which the caller should listen on to catch an eventual run error from the underlying run function, as well as a `startErr` error which can be non-nil if the service failed to start. Start takes in a context which is monitored for until the run function signals it is ready by closing its ready channel.
func (*RunWrapper) Stop ¶
func (w *RunWrapper) Stop() (err error)
Stop stops the service and is thread safe. It returns a non-nil error in the following cases:
- the underlying run function failed to stop and wrote an error to its `stopError` channel
- the service is already stopped
- the service is already crashed
func (*RunWrapper) String ¶
func (w *RunWrapper) String() string
String returns the name of the service.
type Sequence ¶
type Sequence struct {
// contains filtered or unexported fields
}
Sequence is a sequence of services to start and stop in a pre-defined order. It implements the Service interface itself.
func NewSequence ¶
func NewSequence(settings SequenceSettings) (sequence *Sequence, err error)
NewSequence creates a new sequence of services given the settings, and returns an error if any setting is not valid.
func (*Sequence) Start ¶
Start starts services in the order specified by the sequence of services.
If a service fails to start, the `startErr` is returned and all other running services are stopped in the order specified by the stop sequence of services.
If a service fails after this method call returns without error, all other running services are stopped and the error is returned in the `runError` channel which is then closed. A caller should listen on `runError` until the `Stop` method call fully completes, since a run error can theoretically happen at the same time the caller calls `Stop` on the sequence.
If the sequence is already running then a start error ErrAlreadyStarted is returned.
If the context is canceled, the current service starting is canceled, all already running services are stopped and the context error is wrapped in the `startErr` returned.
func (*Sequence) Stop ¶
Stop stops running services of the sequence in the order specified by the sequence of services. If an error occurs for any of the service stop, the other running services will still be stopped. Only the first non nil service stop error encountered is returned, but the hooks can be used to process each error returned. If the sequence is already stopped, the `ErrAlreadyStopped` error is returned.
type SequenceSettings ¶
type SequenceSettings struct {
// Name is the sequence name, used for hooks and errors.
Name string
// ServicesStart specifies an order of services
// to start and must be set.
ServicesStart []Service
// ServicesStart specifies an order of services
// to stop and must be set.
ServicesStop []Service
// Hooks are hooks to call when starting and stopping
// each service. It defaults to a noop hooks
// implementation.
Hooks Hooks
}
SequenceSettings contains settings for a sequence of services.
type Service ¶
type Service interface {
Starter
Stopper
// String returns the service name.
// It is assumed to be constant over the lifetime of the service.
String() string
}
Service is the interface for a service that can be started, stopped and stringed.
type Starter ¶
type Starter interface {
// String returns the starter name.
// It is assumed to be constant over the lifetime of the starter.
String() string
// Start starts the service.
// On success, it returns a run error channel and a nil error.
// On failure, it returns a nil run error channel and an error.
// If the service crashes, only one single error should be sent in
// the error channel.
// When the service is stopped, the service should NOT send an error
// in the run error channel or close this one.
// Start takes in a context and the implementation should promptly return
// the context error wrapped in `startErr` if the context is canceled.
Start(ctx context.Context) (runError <-chan error, startErr error)
}
Starter is the interface for a service that can be started.
type State ¶
type State uint8
State is the state of a service. Is it exported to ease the implementation of services.
const ( // StateStopped is the state of a service that is stopped. StateStopped State = iota // StateStarting is the state of a service that is starting. StateStarting // StateRunning is the state of a service that is running. StateRunning // StateStopping is the state of a service that is stopping. StateStopping // StateCrashed is the state of a service that has crashed. StateCrashed )
type Stopper ¶
type Stopper interface {
// String returns the stopper name.
// It is assumed to be constant over the lifetime of the stopper.
String() string
// Stops stops the service.
// A service should NOT close or write an error to its run error channel
// if it is stopped.
Stop() (err error)
}
Stopper is the interface for a service that can be stopped.