Documentation
¶
Overview ¶
Package retrier provides a configurable Task retry and backoff mechanism. It includes a worker pool with dynamic scaling, Task submission, and pluggable backoff strategies for scheduling retries.
Package retrier provides a dynamic, auto‑scaling worker pool for concurrent task processing. It supports graceful shutdown, suspension, and configurable limits with idle timeout.
Index ¶
- Constants
- type BackOff
- type BackOffFn
- type BackOffParam
- type BackOffParams
- type BackOffStrategy
- type Breaker
- type CircuitBreaker
- type CircuitBreakerState
- type ErrorState
- type EventPublisher
- type ExecutionError
- type FullWorkerState
- type Logger
- type Manager
- type ManagerWorker
- type MemStore
- type Store
- type Task
- type TaskExecutionResult
- type TaskStatus
- type Worker
- type WorkerConfig
- type WorkerExecutionResult
- type WorkerFn
- type WorkerState
- type WorkerStatus
Constants ¶
const ( LinearBackOff string = "linear" JitterLinearBackOff string = "jitter-linear" ExponentialBackOff string = "exponential" JitterExponentialBackoff string = "jitter-exponential" )
Predefined backoff strategy codes. Register these with the BackOffStrategy.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type BackOff ¶
type BackOff interface {
Get(backOff BackOffParams) (time.Time, error)
}
BackOff defines the interface for computing the next execution time based on backoff parameters.
type BackOffFn ¶
type BackOffFn func(params BackOffParams) (time.Time, error)
BackOffFn is a function that computes the next execution time based on the provided BackOffParams. It returns the scheduled time or an error.
type BackOffParam ¶
type BackOffParam string
BackOffParam defines the allowed parameter keys for backoff strategy configuration.
const ( // DurationKey specifies the fixed duration for linear backoff. DurationKey BackOffParam = "duration" // JitterKey specifies the jitter factor (as a fraction) to add randomness. JitterKey BackOffParam = "jitter" // MultiplierKey specifies the multiplier for exponential backoff. MultiplierKey BackOffParam = "multiplier" // MaxDelayKey specifies the upper bound for the calculated delay. MaxDelayKey BackOffParam = "maxDelay" // BaseDelayKey specifies the initial delay for exponential backoff. BaseDelayKey BackOffParam = "baseDelay" )
type BackOffParams ¶
type BackOffParams interface {
// GetBackOffCode returns the identifier of the desired backoff strategy.
GetBackOffCode() string
// GetBackOffParams returns the map of parameters for the strategy.
GetBackOffParams() map[BackOffParam]interface{}
// GetRetries returns the number of attempts already made.
GetRetries() int
}
BackOffParams is an interface that any Task or configuration must implement to be used with the backoff strategy. It provides the necessary metadata.
type BackOffStrategy ¶
type BackOffStrategy struct {
// contains filtered or unexported fields
}
BackOffStrategy manages a registry of named backoff strategies and provides a thread-safe way to compute the next execution time.
func NewBackOffStrategy ¶
func NewBackOffStrategy() *BackOffStrategy
NewBackOffStrategy creates a new BackOffStrategy pre‑registered with the four standard strategies: linear, jitter‑linear, exponential, and jitter‑exponential.
func (*BackOffStrategy) Get ¶
func (s *BackOffStrategy) Get(backOff BackOffParams) (time.Time, error)
Get computes the next execution time using the strategy identified by the BackOffParams. It returns an error if the strategy is not registered.
func (*BackOffStrategy) Register ¶
func (s *BackOffStrategy) Register(code string, fn BackOffFn)
Register adds or overwrites a backoff strategy under the given code. This method is safe for concurrent use.
type Breaker ¶
type Breaker interface {
Allow() bool
RecordSuccess()
RecordFailure()
State() CircuitBreakerState
Reset()
}
Breaker defines the public interface for a circuit breaker.
type CircuitBreaker ¶
type CircuitBreaker struct {
// contains filtered or unexported fields
}
CircuitBreaker implements a circuit breaker using a sliding time window. It tracks success/failure counts over a configurable window duration and opens the circuit when the failure rate exceeds a given threshold.
func NewSlidingWindowCircuitBreaker ¶
func NewSlidingWindowCircuitBreaker( windowSize time.Duration, failureThreshold float64, minRequests int, timeout time.Duration, ) *CircuitBreaker
NewSlidingWindowCircuitBreaker creates a new circuit breaker with sliding window. Parameters:
windowSize: duration of the sliding window failureThreshold: allowed failure ratio (e.g., 0.5 means 50% failures) minRequests: minimum number of requests required before evaluating threshold timeout: duration to wait in open state before attempting half-open
func (*CircuitBreaker) Allow ¶
func (cb *CircuitBreaker) Allow() bool
Allow checks if a request is permitted.
func (*CircuitBreaker) RecordFailure ¶
func (cb *CircuitBreaker) RecordFailure()
RecordFailure records a failure execution.
func (*CircuitBreaker) RecordSuccess ¶
func (cb *CircuitBreaker) RecordSuccess()
RecordSuccess records a successful execution.
func (*CircuitBreaker) Reset ¶
func (cb *CircuitBreaker) Reset()
Reset manually resets the circuit to closed state and clears windows.
func (*CircuitBreaker) State ¶
func (cb *CircuitBreaker) State() CircuitBreakerState
State returns the current state (thread-safe).
type CircuitBreakerState ¶
type CircuitBreakerState string
CircuitBreakerState represents the state of a circuit breaker.
const ( // StateClosed CB state StateClosed CircuitBreakerState = "closed" // StateOpen CB state StateOpen CircuitBreakerState = "open" // StateHalfOpen CB state StateHalfOpen CircuitBreakerState = "half-open" )
type ErrorState ¶
type ErrorState string
ErrorState classifies errors for retry or abort decisions.
const ( // CriticalState marks errors that are unrecoverable (e.g., validation failures). // Tasks with critical errors should not be retried. CriticalState ErrorState = "critical" // UsualState marks transient errors (e.g., network timeouts) that may be retried. UsualState ErrorState = "usual" )
type EventPublisher ¶
type EventPublisher interface {
Publish(event WorkerExecutionResult)
}
EventPublisher if we need to get Task and Task results immediately we can add published for send tasks
type ExecutionError ¶
type ExecutionError struct {
Err error
State ErrorState
}
ExecutionError wraps an error with a state that indicates whether the error is critical.
type FullWorkerState ¶
type FullWorkerState struct {
Status WorkerStatus `json:"status"`
ActiveTasks int32 `json:"active_tasks"`
ActiveWorkers int32 `json:"active_workers"`
CBState CircuitBreakerState `json:"cb_state"`
}
FullWorkerState worker state with data from Circuit Breaker
type Logger ¶
type Logger interface {
Infof(format string, args ...interface{})
Errorf(format string, args ...interface{})
}
Logger specifies the logging capability required by the retry manager.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager orchestrates worker pools, routes execution results to storage, and buffers data locally in-memory during storage outages.
func NewManager ¶
func NewManager( ctx context.Context, store Store, logger Logger, backOff BackOff, maxBufferSize int, fetchTaskTimeout time.Duration, fetchTaskTimeoutMax time.Duration, eventPublisher EventPublisher, ) *Manager
NewManager initializes a new Manager with the required dependencies and configurations.
func (*Manager) GetWorkerStatuses ¶
func (m *Manager) GetWorkerStatuses() map[string]FullWorkerState
GetWorkerStatuses returns a snapshot of the current state of all registered workers.
func (*Manager) RegisterWorker ¶
func (m *Manager) RegisterWorker(name string, w ManagerWorker, b Breaker) error
RegisterWorker adds a new worker with an optional circuit breaker.
func (*Manager) Start ¶
func (m *Manager) Start()
Start boots the manager, launches all registered workers, and spins up pipeline routines.
func (*Manager) Stop ¶
func (m *Manager) Stop()
Stop gracefully shuts down the manager, ensures all results are persisted, and waits for all goroutines to finish.
func (*Manager) UnregisterWorker ¶
UnregisterWorker removes a worker and its associated circuit breaker.
type ManagerWorker ¶
type ManagerWorker interface {
Start()
Stop()
Submit(t *Task) error
GetOutChan() chan WorkerExecutionResult
GetStatus() WorkerState
}
ManagerWorker defines the contract for a component capable of processing tasks and streaming execution results asynchronously.
type MemStore ¶
type MemStore struct {
// contains filtered or unexported fields
}
MemStore is an in-memory implementation of the Store interface. It retains only tasks that are not yet finished (pending or suspended), allowing them to be retried. Completed tasks (success or permanent failure) are skipped during SaveTask.
This implementation is intended for testing and demonstration purposes only. For production use, consider a persistent store with proper indexing and transaction support.
func (*MemStore) GetTasks ¶
GetTasks returns all tasks currently stored in memory. It returns a copy of the internal slice to avoid external modifications.
func (*MemStore) SaveTask ¶
func (ms *MemStore) SaveTask(t *Task, _ *TaskExecutionResult) error
SaveTask stores a Task if it is not yet finished (status is not "success" or "failure"). If a Task with the same ID already exists, it is updated in place. This ensures that retry counts, status, and NextRun are kept current.
type Store ¶
type Store interface {
GetTasks() ([]Task, error)
SaveTask(task *Task, result *TaskExecutionResult) error
}
Store abstracts persistence layer operations for logging and auditing Task outcomes.
type Task ¶
type Task struct {
// ID uniquely identifies this Task across the entire system.
ID uuid.UUID `json:"id"`
// Ctx context for tracing
Ctx context.Context `json:"-"`
// Payload holds the strongly-typed input arguments required for Task execution.
Payload []byte `json:"payload"`
// ManagerWorker specifies the designated runner type or queue name for this Task.
Worker string `json:"worker"`
// Status tracks the current lifecycle phase of the Task (e.g., pending, running, failed).
Status TaskStatus `json:"status"`
// Retries count of execution times
Retries int `json:"retries"`
// MaxRetries max tries count
MaxRetries int `json:"max_retries"`
// BackOffCode code of back off strategy
BackOffCode string `json:"backoff_code"`
// BackOffParams params for back off strategy
BackOffParams map[BackOffParam]interface{} `json:"backoff_params"`
// Deadline is an optional time limit for Task completion.
// If the current time exceeds this deadline before the Task starts executing,
// the Task will be marked as failed with a critical error and will not be retried.
// Zero value (time.Time{}) indicates no deadline.
Deadline time.Time `json:"deadline"`
// CreatedAt records the exact timestamp when the Task was initially created.
CreatedAt time.Time `json:"created_at"`
// LastRun records the timestamp of the most recent execution attempt, if any.
LastRun time.Time `json:"last_run"`
// NextRun records the scheduled timestamp when the Task should be picked up next.
NextRun time.Time `json:"next_run"`
}
Task represents a generic executable unit of work with retry tracking.
func (*Task) GetBackOffCode ¶
GetBackOffCode returns the backoff strategy code.
func (*Task) GetBackOffParams ¶
func (t *Task) GetBackOffParams() map[BackOffParam]interface{}
GetBackOffParams returns the parameters for the backoff strategy.
func (*Task) GetRetries ¶
GetRetries returns the current retry count.
func (*Task) IsFinished ¶
IsFinished is Task finished and will not be retried
type TaskExecutionResult ¶
type TaskExecutionResult struct {
// ID uniquely identifies this specific execution outcome record.
ID uuid.UUID
// TaskID references the parent Task that generated this execution Result.
TaskID uuid.UUID
// Status indicates whether this specific run succeeded or encountered an error.
Status TaskStatus
// RunAt records the exact timestamp when this execution attempt was performed.
RunAt time.Time
// Result stores the raw payload returned by the workerImpl, such as response data or error details.
Result []byte
// IsCritical if this is a validation error, we have no any tries
IsCritical bool
// ExecutionTime worker func duration
ExecutionTime time.Duration
}
TaskExecutionResult records the outcome and metadata of a single execution attempt of a Task.
type TaskStatus ¶
type TaskStatus string
TaskStatus Task status
const ( // StatusPending Task status StatusPending TaskStatus = "pending" // StatusSuccess Task status StatusSuccess TaskStatus = "success" // StatusFailure Task status StatusFailure TaskStatus = "failure" )
type Worker ¶
type Worker struct {
// contains filtered or unexported fields
}
Worker manages a dynamic pool of goroutines that process tasks from an input queue. It scales up when all workers are busy (up to maxWorkers) and scales down when workers are idle for idleTimeout (down to minWorkers). It provides thread‑safe operations for starting, stopping, suspending, and submitting tasks.
func NewWorker ¶
NewWorker constructs a new worker pool with the given configuration and processing function. The pool starts in the Created state; call Start() to begin processing.
func (*Worker) GetOutChan ¶
func (w *Worker) GetOutChan() chan WorkerExecutionResult
GetOutChan returns the output channel where completed task results are delivered. The channel is closed when the pool is stopped. If the pool is restarted after Stop, a new channel is created; callers should obtain the new channel again.
func (*Worker) GetStatus ¶
func (w *Worker) GetStatus() WorkerState
GetStatus returns a snapshot of the pool's current state. It is safe to call concurrently.
func (*Worker) Start ¶
func (w *Worker) Start()
Start transitions the pool into the Running state and spawns the minimum number of workers. If the pool is already Running, it does nothing. If it was Suspended, it cancels the previous context to terminate old workers and starts fresh. If it was Stopped, it re‑creates the internal channels (since they were closed by Stop), resets all counters, and starts a new generation of workers. After Start returns, the pool is ready to accept tasks again.
func (*Worker) Stop ¶
func (w *Worker) Stop()
Stop permanently shuts down the pool. It cancels all workers, waits for them to finish, and closes the input and output channels. After Stop, the pool can be restarted by calling Start() (which will recreate the channels). It is safe to call multiple times.
func (*Worker) Submit ¶
Submit enqueues a task for processing. It attempts a non‑blocking send first; if no worker is idle, it scales up (if possible) and then blocks until the task is accepted or the pool is cancelled/stopped. Returns an error if the pool is not Running.
func (*Worker) Suspend ¶
func (w *Worker) Suspend()
Suspend puts the pool into the Suspended state. It does not cancel existing tasks; it only prevents new submissions. Active tasks continue to completion. The pool can be resumed by calling Start() again.
func (*Worker) UpdateConfig ¶ added in v1.1.0
func (w *Worker) UpdateConfig(cfg *WorkerConfig)
UpdateConfig replaces the current configuration with a new one. The change takes effect immediately for subsequent scaling decisions and idle timeouts. It is safe to call concurrently.
type WorkerConfig ¶ added in v1.1.0
type WorkerConfig struct {
// contains filtered or unexported fields
}
WorkerConfig holds the tunable parameters for the worker pool.
func NewWorkerCfg ¶ added in v1.1.0
func NewWorkerCfg(min, max int32, idleTimeout time.Duration) (*WorkerConfig, error)
NewWorkerCfg creates a validated WorkerConfig. Returns an error if min > max, any value is negative, or idleTimeout <= 0.
type WorkerExecutionResult ¶
type WorkerExecutionResult struct {
Task *Task
Result *TaskExecutionResult
}
WorkerExecutionResult pairs the original Task with its execution result.
type WorkerFn ¶
type WorkerFn func(ctx context.Context, payload []byte) (string, *ExecutionError)
WorkerFn is the user‑defined function that processes a task payload. It returns a result string and an optional ExecutionError. If the function panics, it is recovered and treated as a critical error.
type WorkerState ¶
type WorkerState struct {
Status WorkerStatus `json:"status"`
ActiveTasks int32 `json:"active_tasks"` // number of tasks currently being processed
ActiveWorkers int32 `json:"active_workers"` // number of running worker goroutines
}
WorkerState is a snapshot of the pool's current status.
type WorkerStatus ¶
type WorkerStatus string
WorkerStatus represents the current lifecycle state of the worker pool.
const ( // WorkerStatusCreated indicates the pool is initialized but not yet started. WorkerStatusCreated WorkerStatus = "created" // WorkerStatusRunning indicates the pool is actively accepting and executing tasks. WorkerStatusRunning WorkerStatus = "running" // WorkerStatusStopped indicates the pool is completely shut down and cannot be reused. WorkerStatusStopped WorkerStatus = "stopped" // WorkerStatusSuspended indicates the pool is temporarily paused; active tasks are drained, // and new submissions are rejected. WorkerStatusSuspended WorkerStatus = "suspended" )