Documentation ¶
Index ¶
- Variables
- func AbortRetry(err error) error
- func MapSetNow(m *Map, now func() time.Time) func()
- type ApplyFunc
- type Change
- type CreateFunc
- type IdFunc
- type Lifecycle
- type Map
- func (m *Map) Create(id, kind string, state State) (string, State, error)
- func (m *Map) Delete(id string) (State, error)
- func (m *Map) Get(id string) *Record
- func (m *Map) GetAndListen(ctx context.Context) ([]*Record, <-chan *Change)
- func (m *Map) GetAndListenState(ctx context.Context) ([]*StateRecord, <-chan *StateChange)
- func (m *Map) Listen(ctx context.Context) <-chan *Change
- func (m *Map) States() []*StateRecord
- func (m *Map) Values() []*Record
- type Option
- type OptionFunc
- type ParseFunc
- type Record
- type RetryContext
- type RetryOption
- type Service
- func (l *Service[C]) Configure(data []byte) (State, error)
- func (l *Service[C]) Start() (State, error)
- func (l *Service[C]) State() State
- func (l *Service[C]) StateAndChanges(ctx context.Context) (State, <-chan State)
- func (l *Service[C]) StateChanges(ctx context.Context) <-chan State
- func (l *Service[C]) Stop() (State, error)
- type State
- type StateChange
- type StateRecord
Constants ¶
This section is empty.
Variables ¶
var ( // IdIsKind is an IdFunc that attempts to use the kind as the id. // This implies that only one service of a given type can exist in the map. IdIsKind = IdFunc(func(kind string, exists func(id string) bool) (string, error) { if exists(kind) { return "", errors.New("id exists") } return kind, nil }) IdIsUUID = IdFunc(func(kind string, exists func(id string) bool) (string, error) { max := 10 for i := 0; i < max; i++ { id := uuid.New() if exists(id) { continue } return id, nil } return "", errors.New("exhausted attempts finding unique uuid") }) IdIsRequired = IdFunc(func(_ string, _ func(id string) bool) (string, error) { return "", errors.New("id is required") }) )
var ( // ErrAlreadyStarted is returned from Service.Start if the service state is active. ErrAlreadyStarted = errors.New("already started") // ErrAlreadyStopped is returned from Service.Stop if the service state is not active. ErrAlreadyStopped = errors.New("already stopped") // ErrAlreadyLoading is returned from Service.Configure if the service state is loading. ErrAlreadyLoading = errors.New("already loading") )
var ErrImmutable = errors.New("immutable")
var (
ErrNotFound = errors.New("not found")
)
Functions ¶
func AbortRetry ¶
AbortRetry returns a new error wrapping err that when returned from an ApplyFunc passed to RetryApply will cause it to not attempt a retry.
Types ¶
type ApplyFunc ¶
ApplyFunc is called each time an active service has its config updated. The func should block for as long as config is being read but no longer. Background tasks, like opening connections to other network devices, should not block. The given context will be cancelled if the Service is stopped.
Only one call to ApplyFunc will happen at the same time, but it may be called more than once if Service.Configure is called on an active service. The implementation is responsible for cleaning up any outdated resources as part of the second ApplyFunc call.
func MonoApply ¶
MonoApply wraps apply to ensure that consecutive calls to the returned ApplyFunc will cancel the context passed to apply.
func RetryApply ¶
func RetryApply[C any](apply ApplyFunc[C], opts ...RetryOption) ApplyFunc[C]
RetryApply wraps apply, recalling it until it does not return an error or the context is canceled. Backoff will be applied between calls to apply.
type Change ¶
type Change struct { ChangeTime time.Time ChangeType types.ChangeType OldValue *Record NewValue *Record // contains filtered or unexported fields }
Change represents a change to a Map.
type CreateFunc ¶
CreateFunc returns a new Lifecycle for the given kind. CreateFunc is called during Map.Create.
type IdFunc ¶
IdFunc generates a new id given the passed parameters. The function should return an error if no id can be found for which exists(id) returns false. IdFunc is called during Map.Create to mint new IDs where they are not provided as part of the call.
type Map ¶
type Map struct {
// contains filtered or unexported fields
}
Map tracks multiple Record with the ability to create, delete, and listen for changes to the tracked records.
func NewMap ¶
func NewMap(createFunc CreateFunc, idFunc IdFunc) *Map
NewMap creates and returns a new empty Map using the given create funcs.
func NewMapOf ¶
NewMapOf creates an immutable map containing only the given known services. Services will have an ID assigned based on the index in known. The returned map will return an error for Create and Delete.
func (*Map) Create ¶
Create creates and adds a new record to m returning the new ID and the records service State. The kind argument is required, but id is optional. If absent the IdFunc will be used to mint a new ID. Only State.Active and State.Config are optionally used in the passed state to either Start or Configure the created Lifecycle. If either are present and the corresponding Lifecycle call returns an error, then creating the new record will be aborted and that error will be returned.
func (*Map) Delete ¶
Delete stops and removes the record with the given ID from m. If id is not found, returns ErrNotFound. Delete does not error if the record is already stopped.
func (*Map) GetAndListen ¶
func (*Map) GetAndListenState ¶
func (m *Map) GetAndListenState(ctx context.Context) ([]*StateRecord, <-chan *StateChange)
func (*Map) States ¶
func (m *Map) States() []*StateRecord
States returns all known states in an indeterminate order.
type Option ¶
type Option[T any] interface { // contains filtered or unexported methods }
func DefaultOpts ¶
func WithNow ¶
WithNow configures a service with a custom time functions instead of the default time.Now. Useful for testing.
func WithOnStop ¶
WithOnStop sets a function on the Service that will be called each time Service.Stop is executed. The onStop func should not invoke any lifecycle methods on the created service as this may result in a deadlock.
func WithParser ¶
WithParser configures a Service to use the given parse func instead of the default json.Unmarshaler.
func WithRetry ¶
func WithRetry[T any](opts ...RetryOption) Option[T]
WithRetry configures a service to retry ApplyFunc when it returns an error.
type OptionFunc ¶
OptionFunc adapts a func of the correct signature to implement Option.
type ParseFunc ¶
ParseFunc is called to convert raw []byte config into a known config structure. The func is called in line with calls to Service.Configure and any errors are reported immediately. The func should perform any validation on the configuration in order to avoid errors once the parsed config is passed to ApplyFunc.
type RetryContext ¶
type RetryOption ¶
type RetryOption func(*retryOptions)
func RetryWithFactor ¶
func RetryWithFactor(f float64) RetryOption
func RetryWithInitialDelay ¶
func RetryWithInitialDelay(d time.Duration) RetryOption
func RetryWithLogger ¶
func RetryWithLogger(l func(logContext RetryContext)) RetryOption
func RetryWithMaxAttempts ¶
func RetryWithMaxAttempts(n int) RetryOption
func RetryWithMaxDelay ¶
func RetryWithMaxDelay(d time.Duration) RetryOption
type Service ¶
type Service[C any] struct { // contains filtered or unexported fields }
Service manages the lifecycle of a background task.
func New ¶
New creates a new Service using apply to spin up background tasks based on config of type C. The default ParserFunc uses json.Unmarshal to convert []byte to C. The service is created inactive and without config.
func (*Service[C]) Configure ¶
Configure updates the config associated with this service. If the service is active then the config will be loaded as part of this call without blocking. If ParseFunc returns an error parsing data, that error will be returned and no state transition will be applied.
func (*Service[C]) Start ¶
Start transitions the Service to the active state. If the service has config then that config will be loaded as part of this call without blocking. Starting an active service returns ErrAlreadyStarted.
func (*Service[C]) StateAndChanges ¶
StateAndChanges atomically returns the current state and a chan that emits future state changes.
func (*Service[C]) StateChanges ¶
StateChanges returns a chan that will emit each time the service state changes.
type State ¶
type State struct { // Active records whether a Service is performing its job or not. // If true then the Service is doing what it is designed to do, it potentially has running background tasks, and is responding to stimulus. // If false then the Service is stopped, is not doing any work, and has no background processes active. // Active is updated via Service.Start and Service.Stop. // Additionally if a service fails to load config then this can also cause the Service to become inactive with an error. Active bool // Config is the raw configuration bytes last successfully used to configure the Service. // The contents of Config should not be modified after calling Configure Config []byte // Loading indicates that the service is Active and is processing an update to config. // If configured to retry and loading fails, this will remain true but Err and NextAttemptTime will be set. Loading bool // Err holds the error returned by the ApplyFunc. Err error // FailedAttempts records how many start attempts have resulted in error. // This is reset on stop and when the configuration is updated. FailedAttempts int // Times active was last set to false or true respectively. LastInactiveTime, LastActiveTime time.Time // Times these fields were last filled. // Setting err to nil does not update the time. LastErrTime, LastConfigTime time.Time // Times when loading was set to true or false respectively. // lastLoadingEndTime will be set to the zero time when loading is set to true. LastLoadingStartTime, LastLoadingEndTime time.Time // The time the service will next attempt to load. // An active service that fails to load may attempt to retry the load, this is the time of that attempt. NextAttemptTime time.Time }
State contains all the properties of the service. A services state can be fetched on demand or you can be notified of changes via the Service.State, Service.StateChanges, and Service.StateAndChanges depending on your needs.
type StateChange ¶
type StateChange struct { ChangeTime time.Time ChangeType types.ChangeType OldValue *StateRecord NewValue *StateRecord }