jobs

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Sep 27, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package jobs provides a common abstraction for background jobs: handlers, dispatching, worker lifecycle, retries with backoff, observability hooks and graceful shutdown. Queue infrastructure is supplied by adapters implementing Queue (Redis, PostgreSQL, SQS, RabbitMQ, NATS, ...); MemoryQueue is included for development and tests.

m := jobs.NewManager(jobs.Options{Queue: queue})
m.Register("send-email", jobs.Typed(func(ctx context.Context, p Email) error {
    return mailer.Send(ctx, p)
}))
_ = m.Dispatch(ctx, "send-email", Email{To: "a@example.com"})

Index

Constants

View Source
const (
	MetaRequestID = "request_id"
	MetaTraceID   = "trace_id"
)

Metadata keys set by Dispatch.

Variables

View Source
var ErrQueueClosed = errors.New("jobs: queue closed")

ErrQueueClosed is returned when enqueuing into a closed MemoryQueue.

View Source
var ErrUnknownJob = errors.New("jobs: unknown job")

ErrUnknownJob is returned when dispatching a job name with no handler.

Functions

func ExponentialBackoff

func ExponentialBackoff(base, max time.Duration) func(int) time.Duration

ExponentialBackoff returns base*2^(attempt-1) capped at max, with up to 20% random jitter to avoid synchronized retries.

func IsPermanent

func IsPermanent(err error) bool

IsPermanent reports whether err was marked with Permanent.

func Permanent

func Permanent(err error) error

Permanent marks an error as non-retryable.

Types

type Delivery

type Delivery interface {
	Job() *Job
	// Ack marks the job as processed.
	Ack(ctx context.Context) error
	// Retry schedules redelivery after delay with Attempt incremented.
	Retry(ctx context.Context, delay time.Duration) error
	// Reject marks the job as permanently failed (dead-lettered when the
	// backend supports it).
	Reject(ctx context.Context, reason error) error
}

Delivery is a received job awaiting acknowledgment.

type DispatchOption

type DispatchOption func(*Job, *time.Duration)

DispatchOption configures a dispatch.

func Delay

func Delay(d time.Duration) DispatchOption

Delay schedules the job to run after d.

func WithID

func WithID(id string) DispatchOption

WithID sets the job ID, which backends may use for deduplication.

type Handler

type Handler interface {
	Handle(ctx context.Context, job *Job) error
}

Handler processes jobs. Handlers must honor ctx cancellation.

func Typed

func Typed[T any](fn func(ctx context.Context, payload T) error) Handler

Typed adapts a function taking a decoded payload.

type HandlerFunc

type HandlerFunc func(ctx context.Context, job *Job) error

HandlerFunc adapts a function to Handler.

func (HandlerFunc) Handle

func (f HandlerFunc) Handle(ctx context.Context, job *Job) error

Handle implements Handler.

type Job

type Job struct {
	ID          string            `json:"id"`
	Name        string            `json:"name"`
	Payload     json.RawMessage   `json:"payload,omitempty"`
	Attempt     int               `json:"attempt"`
	MaxAttempts int               `json:"max_attempts,omitempty"`
	EnqueuedAt  time.Time         `json:"enqueued_at"`
	Metadata    map[string]string `json:"metadata,omitempty"`
}

Job is a unit of background work.

func (*Job) Decode

func (j *Job) Decode(v any) error

Decode unmarshals the payload into v.

type JobOption

type JobOption func(*registration)

JobOption configures a registered job.

func MaxAttempts

func MaxAttempts(n int) JobOption

MaxAttempts overrides the attempt limit for a job.

func Timeout

func Timeout(d time.Duration) JobOption

Timeout overrides the per-attempt timeout for a job.

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager registers handlers, dispatches jobs and runs workers. It implements Start and Stop so it can be managed by an application lifecycle.

func NewManager

func NewManager(opts Options) *Manager

NewManager returns a Manager. It panics if opts.Queue is nil.

func (*Manager) Dispatch

func (m *Manager) Dispatch(ctx context.Context, name string, payload any, opts ...DispatchOption) error

Dispatch enqueues a job. payload is JSON-encoded unless it is already []byte or json.RawMessage. The request and trace IDs in ctx are recorded so job logs correlate with the originating request. When handlers are registered, dispatching an unknown name fails with ErrUnknownJob; a manager without handlers (dispatch-only) accepts any name.

func (*Manager) Names

func (m *Manager) Names() []string

Names returns the registered job names.

func (*Manager) Queue

func (m *Manager) Queue() Queue

Queue returns the manager's queue.

func (*Manager) Register

func (m *Manager) Register(name string, h Handler, opts ...JobOption) error

Register adds a handler for name. It fails if name is already registered or the manager is running.

func (*Manager) Start

func (m *Manager) Start(context.Context) error

Start launches the workers. It returns immediately.

func (*Manager) Stop

func (m *Manager) Stop(ctx context.Context) error

Stop stops receiving new jobs and waits for in-flight jobs. If ctx expires first, running jobs are canceled and Stop returns ctx.Err() after they return.

type MemoryQueue

type MemoryQueue struct {
	// contains filtered or unexported fields
}

MemoryQueue is an in-process queue for development and tests. Jobs are lost when the process exits and are not shared between instances; use a durable backend in production.

func NewMemoryQueue

func NewMemoryQueue(capacity int) *MemoryQueue

NewMemoryQueue returns a queue buffering up to capacity ready jobs (default 1024). Enqueue blocks while the buffer is full.

func (*MemoryQueue) Close

func (q *MemoryQueue) Close() error

Close stops pending delayed deliveries and rejects further enqueues.

func (*MemoryQueue) Enqueue

func (q *MemoryQueue) Enqueue(ctx context.Context, job *Job, delay time.Duration) error

Enqueue implements Queue.

func (*MemoryQueue) Failed

func (q *MemoryQueue) Failed() []*Job

Failed returns permanently failed jobs (the dead-letter list).

func (*MemoryQueue) IsLocal

func (q *MemoryQueue) IsLocal() bool

IsLocal reports that the queue's state is process-local.

func (*MemoryQueue) Len

func (q *MemoryQueue) Len() int

Len returns the number of jobs ready for delivery.

func (*MemoryQueue) Receive

func (q *MemoryQueue) Receive(ctx context.Context) (Delivery, error)

Receive implements Queue.

type Middleware

type Middleware func(Handler) Handler

Middleware wraps job handlers, for example for tracing or metrics.

type Options

type Options struct {
	// Queue is the backend. Required.
	Queue Queue
	// Workers is the number of concurrent workers (default GOMAXPROCS).
	// Set to -1 for a dispatch-only manager that never consumes.
	Workers int
	// MaxAttempts is the default attempt limit per job (default 3).
	MaxAttempts int
	// Timeout bounds a single attempt (default 5m).
	Timeout time.Duration
	// Backoff returns the delay before retry number attempt (1-based).
	// Default: exponential from 1s, capped at 5m, with jitter.
	Backoff func(attempt int) time.Duration
	// Logger receives job failures (default slog.Default()).
	Logger *slog.Logger
	// Middleware wraps every handler; the first is outermost.
	Middleware []Middleware
	// OnFailure is called when a job fails permanently.
	OnFailure func(ctx context.Context, job *Job, err error)
}

Options configures a Manager.

type Queue

type Queue interface {
	// Enqueue stores job for delivery after delay.
	Enqueue(ctx context.Context, job *Job, delay time.Duration) error
	// Receive blocks until a job is available or ctx is done, in which case
	// it returns ctx.Err().
	Receive(ctx context.Context) (Delivery, error)
}

Queue is implemented by queue backends.

Jump to

Keyboard shortcuts

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