Documentation
¶
Overview ¶
Package chronos is a Redis-backed distributed scheduler and task queue.
Index ¶
- Constants
- Variables
- func AddHandler[T TaskArgs](mux *Mux, fn func(ctx context.Context, task *Task[T]) error)
- func DefaultRetryDelay(retried int, _ error) time.Duration
- func RegisterCron[T TaskArgs](s *Scheduler, spec string, args T, opts ...Option) error
- func RegisterInterval[T TaskArgs](s *Scheduler, interval time.Duration, args T, opts ...Option) error
- func SkipRetry(err error) error
- type Client
- type Inspector
- func (i *Inspector) DeleteTask(ctx context.Context, qname, taskID string) error
- func (i *Inspector) GetTask(ctx context.Context, qname, taskID string) (*TaskInfo, error)
- func (i *Inspector) ListTasks(ctx context.Context, qname, state string, limit int) ([]*TaskInfo, error)
- func (i *Inspector) Queues(ctx context.Context) ([]*QueueInfo, error)
- func (i *Inspector) RunTask(ctx context.Context, qname, taskID string) error
- type Metrics
- type MisfirePolicy
- type Mux
- type Option
- func WithDeadLetterDiscard() Option
- func WithMaxRetry(n int) Option
- func WithMisfirePolicy(p MisfirePolicy) Option
- func WithProcessAt(t time.Time) Option
- func WithProcessIn(d time.Duration) Option
- func WithQueue(name string) Option
- func WithTaskID(id string) Option
- func WithUnique(ttl time.Duration) Option
- type QueueInfo
- type RetryDelayFunc
- type Scheduler
- type SchedulerConfig
- type Server
- type ServerConfig
- type Task
- type TaskArgs
- type TaskInfo
- type TaskOutcome
Constants ¶
const DefaultMaxRetry = 25
DefaultMaxRetry is the retry budget used when WithMaxRetry is not given.
const DefaultQueue = "default"
DefaultQueue is the queue used when none is specified.
Variables ¶
var ( ErrTaskNotFound = errors.New("chronos: task not found") ErrInvalidState = errors.New("chronos: invalid task state") )
Errors returned by the Inspector, exposed so callers (e.g. the web console) can map them to the right response.
var ErrDuplicateTask = rdb.ErrDuplicateTask
ErrDuplicateTask is returned by Enqueue when WithUnique is used and an identical task already holds the unique lock.
Functions ¶
func AddHandler ¶
AddHandler registers a strongly-typed handler for tasks of type T. The Kind is read from the zero value of T, so T's Kind method must use a value receiver. Registering two handlers for the same Kind panics.
func DefaultRetryDelay ¶
DefaultRetryDelay is the default backoff: an exponential cap (base * 2^retried, clamped to retryMaxDelay) with full jitter — the actual delay is uniformly random in [0, cap]. Full jitter spreads retries to avoid thundering herds.
func RegisterCron ¶
RegisterCron registers args to be enqueued on a standard 5-field cron spec.
func RegisterInterval ¶
func RegisterInterval[T TaskArgs](s *Scheduler, interval time.Duration, args T, opts ...Option) error
RegisterInterval registers args to be enqueued every interval (>= 1s). Any sub-second component is truncated to whole seconds (e.g. 1500ms behaves as 1s). Register all schedules before calling Start (registration is not concurrency- safe with the running tick loop).
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client enqueues tasks.
func NewClient ¶
func NewClient(r redis.UniversalClient) *Client
NewClient returns a Client backed by the given Redis client.
type Inspector ¶
type Inspector struct {
// contains filtered or unexported fields
}
Inspector provides read and administrative access to queues and tasks. It is the foundation the CLI (and any future UI) is built on.
func NewInspector ¶
func NewInspector(r redis.UniversalClient) *Inspector
NewInspector returns an Inspector backed by the given Redis client.
func (*Inspector) DeleteTask ¶
DeleteTask removes a scheduled/retry/archived task and releases its unique lock.
func (*Inspector) GetTask ¶ added in v0.3.0
GetTask returns full detail for a single stored task (scheduled/retry/archived).
func (*Inspector) ListTasks ¶
func (i *Inspector) ListTasks(ctx context.Context, qname, state string, limit int) ([]*TaskInfo, error)
ListTasks returns up to limit tasks in the given state (scheduled|retry|archived).
type Metrics ¶
type Metrics interface {
ObserveTask(queue, kind string, outcome TaskOutcome, dur time.Duration)
}
Metrics receives one observation per processed task. Implementations MUST be safe for concurrent use (the server calls it from worker goroutines). The zero/nil Metrics disables observation. The Prometheus implementation lives in the contrib/prometheus module so the core stays dependency-free.
type MisfirePolicy ¶
type MisfirePolicy int
MisfirePolicy decides what happens when a schedule's triggers were missed (e.g. during a leader-election gap or downtime).
const ( // MisfireSkip (default) discards missed triggers and resumes on schedule. MisfireSkip MisfirePolicy = iota // MisfireFireOnce fires exactly one catch-up trigger if any were missed. MisfireFireOnce )
type Mux ¶
type Mux struct {
// contains filtered or unexported fields
}
Mux routes tasks to handlers by their Kind.
type Option ¶
type Option interface {
// contains filtered or unexported methods
}
Option customizes a single Enqueue call.
func WithDeadLetterDiscard ¶
func WithDeadLetterDiscard() Option
WithDeadLetterDiscard discards the task on retry exhaustion instead of storing it in the archived ZSET. The OnDeadLetter hook still fires.
func WithMaxRetry ¶
WithMaxRetry sets the maximum number of retries before the task is dead-lettered. Defaults to DefaultMaxRetry.
func WithMisfirePolicy ¶
func WithMisfirePolicy(p MisfirePolicy) Option
WithMisfirePolicy sets how a scheduled job handles missed triggers (after a leader-election gap or downtime). Only meaningful for RegisterInterval / RegisterCron; ignored by a plain Enqueue. Defaults to MisfireSkip.
func WithProcessAt ¶
WithProcessAt schedules the task to first become available at t. A non-future time enqueues immediately.
func WithProcessIn ¶
WithProcessIn schedules the task to first become available after d. A non-positive d enqueues immediately.
func WithTaskID ¶
WithTaskID sets an explicit task ID. Enforced deduplication is provided by the unique lock introduced in a later milestone; in M1, re-enqueueing with the same ID is not guaranteed to prevent duplicates. When omitted a random UUID is generated.
func WithUnique ¶
WithUnique deduplicates tasks by (kind + payload): while a matching task is anywhere in the pipeline (pending, retrying, scheduled), enqueueing another returns ErrDuplicateTask. The lock is released when the task reaches a terminal state (completed / archived / discarded).
While a task is actively being processed, the server's heartbeat renews the lock's TTL, so a single attempt that runs longer than ttl still holds the lock. ttl mainly bounds the lock for the time a task spends waiting (pending / scheduled / retry backoff) where no worker is renewing it; set it comfortably above the expected total waiting time. For a delayed task the lock TTL is automatically extended to cover the delay.
type QueueInfo ¶
type QueueInfo struct {
Queue string
Pending int64
Active int64
Scheduled int64
Retry int64
Archived int64
}
QueueInfo is a queue's per-state task counts.
type RetryDelayFunc ¶
RetryDelayFunc computes how long to wait before the next retry, given the number of retries already performed and the error that caused the failure.
type Scheduler ¶
type Scheduler struct {
// contains filtered or unexported fields
}
Scheduler registers periodic jobs and, on whichever instance is elected leader, enqueues their due triggers. Every instance may call Start; only the leader enqueues, and deterministic dedup keys prevent double-enqueue during leader handover.
func NewScheduler ¶
func NewScheduler(r redis.UniversalClient, cfg SchedulerConfig) *Scheduler
NewScheduler returns a Scheduler backed by the given Redis client.
func (*Scheduler) Shutdown ¶
Shutdown stops the scheduler; if this instance is the leader it resigns so a follower can take over immediately.
func (*Scheduler) Start ¶
Start launches leader election and the tick loop. Safe to call on every instance; only the leader enqueues. Register all schedules before Start.
For correct cross-instance behavior, every instance must register the same schedules with the same SchedulerConfig.Location and have reasonably synchronized clocks: the deterministic dedup key is derived from the computed trigger instant, so divergent timezones or badly skewed clocks could let two instances treat the same logical trigger as different ones.
type SchedulerConfig ¶
type SchedulerConfig struct {
// Location is the timezone for cron schedules. Defaults to time.Local.
Location *time.Location
// Logger receives operational logs. Defaults to slog.Default().
Logger *slog.Logger
// LeaderTTL is how long a leadership term lasts before it must be renewed.
// Defaults to 5s. Failover happens within ~LeaderTTL of a leader dying.
LeaderTTL time.Duration
}
SchedulerConfig configures a Scheduler.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server fetches tasks from Redis and dispatches them to handlers.
func NewServer ¶
func NewServer(r redis.UniversalClient, cfg ServerConfig) *Server
NewServer returns a Server backed by the given Redis client.
type ServerConfig ¶
type ServerConfig struct {
// Queues maps queue name to weight. While every queue has work, a queue with
// weight 6 is dequeued about 6x as often as a queue with weight 1 (smooth
// weighted round-robin — no queue starves). When the queue picked for a round
// is empty, that round falls through to the highest-weight queue that does
// have work, so an idle high-priority queue never blocks lower ones. Weights
// <= 0 are treated as 1; very large weights are capped.
Queues map[string]int
// StrictPriority, if true, always drains higher-weight queues first: a
// lower-weight queue is served only while every higher-weight queue is
// empty. Ties are broken by queue name for determinism.
StrictPriority bool
// Concurrency is the max number of tasks processed simultaneously.
Concurrency int
// Logger receives operational logs. Defaults to slog.Default().
Logger *slog.Logger
// RetryDelayFunc computes the backoff before a retry. Defaults to
// DefaultRetryDelay (exponential + full jitter).
RetryDelayFunc RetryDelayFunc
// OnDeadLetter is invoked when a task exhausts its retries (or returns a
// SkipRetry error). It fires whether the task is archived or discarded.
//
// The heartbeat keeps an actively-processing task's lease fresh, so the
// recoverer does not normally reclaim it. It may still fire more than once in
// pathological cases (the server/heartbeat unavailable long enough for the
// lease to lapse), so make the hook idempotent (the archived ZSET entry is
// deduplicated by task ID).
OnDeadLetter func(ctx context.Context, info *TaskInfo, err error)
// Metrics, if set, receives one observation per processed task. Use the
// contrib/prometheus implementation, or your own. Defaults to nil (disabled).
Metrics Metrics
// ForwardInterval is how often the retry ZSET is scanned for due tasks.
// Defaults to 1s.
ForwardInterval time.Duration
// RecoverInterval is how often stuck PEL entries are reclaimed. Defaults to 15s.
RecoverInterval time.Duration
// RecoverMinIdle is how long a PEL entry must be idle before it is treated as
// abandoned. Defaults to 30s when unset (<= 0). The heartbeat refreshes the
// lease of in-flight tasks every HeartbeatInterval, so a task that runs longer
// than RecoverMinIdle is safe as long as this server (its heartbeat) is alive;
// RecoverMinIdle is the window after a worker actually dies before its tasks
// are reclaimed.
RecoverMinIdle time.Duration
// HeartbeatInterval is how often the server refreshes the lease and unique
// lock of in-flight tasks. Defaults to RecoverMinIdle/3. Must be shorter than
// RecoverMinIdle so an actively-processing task is never reclaimed.
HeartbeatInterval time.Duration
// ArchivedRetention is how long a dead-lettered (archived) task is kept
// before the janitor deletes it. Defaults to 7 days (168h).
ArchivedRetention time.Duration
// MaxArchived caps the number of archived tasks per queue; the janitor
// deletes the oldest beyond this even within the retention window. Defaults
// to 10000. Set negative to disable the size cap.
MaxArchived int
// JanitorInterval is how often the janitor runs. Defaults to 1 minute.
JanitorInterval time.Duration
}
ServerConfig configures a Server.
type Task ¶
type Task[T TaskArgs] struct { Args T // contains filtered or unexported fields }
Task is a strongly-typed task delivered to a handler.
type TaskArgs ¶
type TaskArgs interface {
Kind() string
}
TaskArgs is implemented by every task payload type. Kind returns a stable identifier used to route the task to its handler; it MUST be defined on a value receiver so it can be called on the zero value during registration.
type TaskInfo ¶
type TaskInfo struct {
ID string
Kind string
Queue string
// The following are populated by Inspector.ListTasks / GetTask for tasks
// stored in a state ZSET (scheduled / retry / archived).
State string // "scheduled" | "retry" | "archived" | ...
Payload []byte // raw task payload
Retried int // retries already attempted
MaxRetry int // retry budget
LastErr string // most recent failure message ("" if none)
NextProcessAt time.Time // ZSET score as a time: scheduled-for / retry-at / died-at
}
TaskInfo describes an enqueued or stored task. Enqueue returns one with only ID/Kind/Queue set; the Inspector fills the rest for stored tasks.
type TaskOutcome ¶
type TaskOutcome string
TaskOutcome is the terminal result of processing one task, reported to Metrics.
const ( // OutcomeSuccess: the handler returned nil; the task was acked and removed. OutcomeSuccess TaskOutcome = "success" // OutcomeRetry: the handler failed and the task was scheduled for retry. OutcomeRetry TaskOutcome = "retry" // OutcomeDeadLetter: the task exhausted retries (or returned SkipRetry) and // was archived or discarded. OutcomeDeadLetter TaskOutcome = "dead_letter" )
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
chronos
command
Command chronos is a CLI for inspecting and administering chronos-go queues.
|
Command chronos is a CLI for inspecting and administering chronos-go queues. |
|
examples
|
|
|
jobscheduler
Package jobscheduler is a verification adapter proving chronos-go can back operator-review's string+[]byte JobScheduler interface.
|
Package jobscheduler is a verification adapter proving chronos-go can back operator-review's string+[]byte JobScheduler interface. |
|
tour
command
Command tour is a narrated, runnable walkthrough of everything chronos-go can do: the core queue, reliability (retry / dead-letter), delayed + unique tasks, the Inspector, the distributed scheduler with leader failover, the retention janitor, the heartbeat, and weighted priority queues.
|
Command tour is a narrated, runnable walkthrough of everything chronos-go can do: the core queue, reliability (retry / dead-letter), delayed + unique tasks, the Inspector, the distributed scheduler with leader failover, the retention janitor, the heartbeat, and weighted priority queues. |
|
internal
|
|
|
base
Package base defines the Redis key layout, task states, and message serialization shared across chronos-go internals.
|
Package base defines the Redis key layout, task states, and message serialization shared across chronos-go internals. |
|
rdb
Package rdb implements the Redis operations backing chronos-go: enqueueing tasks, dequeueing via a consumer group, and acking completion.
|
Package rdb implements the Redis operations backing chronos-go: enqueueing tasks, dequeueing via a consumer group, and acking completion. |
|
testutil
Package testutil provides shared test helpers for chronos-go.
|
Package testutil provides shared test helpers for chronos-go. |