service

package
v0.2024.5 Latest Latest
Warning

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

Go to latest
Published: Jun 5, 2024 License: GPL-3.0 Imports: 16 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
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")
	})
)
View Source
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")
)
View Source
var ErrImmutable = errors.New("immutable")
View Source
var (
	ErrNotFound = errors.New("not found")
)

Functions

func AbortRetry

func AbortRetry(err error) error

AbortRetry returns a new error wrapping err that when returned from an ApplyFunc passed to RetryApply will cause it to not attempt a retry.

func MapSetNow

func MapSetNow(m *Map, now func() time.Time) func()

MapSetNow sets the now func on m returning a func that undoes the set. Use for testing.

Types

type ApplyFunc

type ApplyFunc[C any] func(ctx context.Context, config C) error

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

func MonoApply[C any](apply ApplyFunc[C]) ApplyFunc[C]

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

type CreateFunc func(kind string) (Lifecycle, error)

CreateFunc returns a new Lifecycle for the given kind. CreateFunc is called during Map.Create.

type IdFunc

type IdFunc func(kind string, exists func(id string) bool) (string, error)

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 Lifecycle

type Lifecycle interface {
	Start() (State, error)
	Configure(data []byte) (State, error)
	Stop() (State, error)

	State() State
	StateChanges(ctx context.Context) <-chan State
	StateAndChanges(ctx context.Context) (State, <-chan State)
}

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

func NewMapOf(known []Lifecycle) *Map

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

func (m *Map) Create(id, kind string, state State) (string, State, error)

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

func (m *Map) Delete(id string) (State, error)

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) Get

func (m *Map) Get(id string) *Record

Get returns the record associated with the given id, or nil if not found.

func (*Map) GetAndListen

func (m *Map) GetAndListen(ctx context.Context) ([]*Record, <-chan *Change)

func (*Map) GetAndListenState

func (m *Map) GetAndListenState(ctx context.Context) ([]*StateRecord, <-chan *StateChange)

func (*Map) Listen

func (m *Map) Listen(ctx context.Context) <-chan *Change

Listen emits changes to m on the returns chan until ctx is done.

func (*Map) States

func (m *Map) States() []*StateRecord

States returns all known states in an indeterminate order.

func (*Map) Values

func (m *Map) Values() []*Record

Values returns all known values in an indeterminate order.

type Option

type Option[T any] interface {
	// contains filtered or unexported methods
}

func DefaultOpts

func DefaultOpts[C any]() []Option[C]

func WithNow

func WithNow[T any](now func() time.Time) Option[T]

WithNow configures a service with a custom time functions instead of the default time.Now. Useful for testing.

func WithOnStop

func WithOnStop[T any](onStop func()) Option[T]

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

func WithParser[T any](parse ParseFunc[T]) Option[T]

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

type OptionFunc[T any] func(l *Service[T])

OptionFunc adapts a func of the correct signature to implement Option.

type ParseFunc

type ParseFunc[C any] func(data []byte) (C, error)

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 Record

type Record struct {
	Id, Kind string
	Service  Lifecycle
}

type RetryContext

type RetryContext struct {
	Attempt int
	Err     error
	Delay   time.Duration // until next attempt, 0 if no more attempts will be performed
	T0      time.Time     // first attempt time
}

func (RetryContext) LogTo

func (ctx RetryContext) LogTo(desc string, logger *zap.Logger)

LogTo logs using a reasonable default format at a reasonable frequency to logger.

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

func New[C any](apply ApplyFunc[C], opts ...Option[C]) *Service[C]

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

func (l *Service[C]) Configure(data []byte) (State, error)

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

func (l *Service[C]) Start() (State, error)

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]) State

func (l *Service[C]) State() State

State returns the current state of the service.

func (*Service[C]) StateAndChanges

func (l *Service[C]) StateAndChanges(ctx context.Context) (State, <-chan State)

StateAndChanges atomically returns the current state and a chan that emits future state changes.

func (*Service[C]) StateChanges

func (l *Service[C]) StateChanges(ctx context.Context) <-chan State

StateChanges returns a chan that will emit each time the service state changes.

func (*Service[C]) Stop

func (l *Service[C]) Stop() (State, error)

Stop transitions the service to the inactive state. The context for any ApplyFunc calls will be cancelled. Config and other state will not be adjusted. If the service is inactive calling Stop will return ErrAlreadyStopped.

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
}

type StateRecord

type StateRecord struct {
	*Record
	State State
}

Jump to

Keyboard shortcuts

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