workflow

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Nov 10, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

Package workflow owns the private workflow protocol and orchestration boundary.

Index

Constants

View Source
const (
	// ProtocolSchemaVersion identifies the workflow delivery envelope understood by this version of the library.
	ProtocolSchemaVersion = 1
	// DirectDeliveryType identifies the retained version-one envelope for legacy
	// direct jobs and application types that collide with reserved protocol names.
	DirectDeliveryType = "bus:job"
	// ChainNodeDeliveryType identifies one sequential workflow node delivery.
	ChainNodeDeliveryType = "bus:chain:node"
	// BatchJobDeliveryType identifies one aggregate workflow member delivery.
	BatchJobDeliveryType = "bus:batch:job"
	// ContinuationDeliveryType identifies the versioned durable continuation delivery protocol.
	ContinuationDeliveryType = "bus:continuation:v1"
	// CallbackDeliveryType identifies one ephemeral workflow callback delivery.
	CallbackDeliveryType = "bus:callback"
)

Variables

View Source
var ErrContinuationProtocol = errors.New("workflow continuation protocol rejected")

ErrContinuationProtocol identifies permanent persisted-protocol or configuration failures.

View Source
var ErrHandlerNotRegistered = errors.New("workflow handler is not registered")

ErrHandlerNotRegistered identifies an absent logical handler without changing its established error text.

View Source
var ErrNotFound = errors.New("bus record not found")

ErrNotFound reports that workflow state is absent from a store.

Functions

func IsDeliveryType

func IsDeliveryType(deliveryType string) bool

IsDeliveryType reports whether a physical job type belongs to the workflow protocol.

Types

type BatchBuilder

type BatchBuilder interface {
	// Name sets a display name for the batch.
	Name(name string) BatchBuilder
	// OnQueue applies a default queue to batch jobs that do not set one.
	OnQueue(queue string) BatchBuilder
	// AllowFailures keeps the batch running when individual jobs fail.
	AllowFailures() BatchBuilder
	// Progress registers a callback invoked as jobs complete.
	Progress(fn func(ctx context.Context, st BatchState) error) BatchBuilder
	// Then registers a callback invoked once when batch succeeds.
	Then(fn func(ctx context.Context, st BatchState) error) BatchBuilder
	// Catch registers a callback invoked when batch encounters a failure.
	Catch(fn func(ctx context.Context, st BatchState, err error) error) BatchBuilder
	// Finally registers a callback invoked once when batch reaches terminal state.
	Finally(fn func(ctx context.Context, st BatchState) error) BatchBuilder
	// Dispatch creates and starts the batch workflow.
	Dispatch(ctx context.Context) (string, error)
}

BatchBuilder configures and dispatches an aggregate workflow.

type BatchJob

type BatchJob struct {
	JobID string
	Job   StoredJob
}

BatchJob binds a stable member identifier to its serialized job.

type BatchJobOutcome

type BatchJobOutcome string

BatchJobOutcome identifies the durable result that first settled one member.

const (
	// BatchJobSucceeded records successful member settlement.
	BatchJobSucceeded BatchJobOutcome = "succeeded"
	// BatchJobFailed records failed member settlement.
	BatchJobFailed BatchJobOutcome = "failed"
)

type BatchRecord

type BatchRecord struct {
	BatchID     string
	DispatchID  string
	Name        string
	Queue       string
	AllowFailed bool
	Jobs        []BatchJob
	CreatedAt   time.Time
	// contains filtered or unexported fields
}

BatchRecord contains the immutable data required to create a batch.

func (BatchRecord) Continuations

func (r BatchRecord) Continuations() []ContinuationDefinition

Continuations returns an isolated named hook catalog from accepted batch input.

type BatchState

type BatchState struct {
	BatchID     string
	DispatchID  string
	Name        string
	Queue       string
	AllowFailed bool
	Total       int
	Pending     int
	Processed   int
	Failed      int
	Cancelled   bool
	Completed   bool
	CreatedAt   time.Time
	UpdatedAt   time.Time
}

BatchState is the persisted aggregate execution view of a batch.

type ChainBuilder

type ChainBuilder interface {
	// OnQueue applies a default queue to chain jobs that do not set one.
	OnQueue(queue string) ChainBuilder
	// Catch registers a callback invoked when chain execution fails.
	Catch(fn func(ctx context.Context, st ChainState, err error) error) ChainBuilder
	// Finally registers a callback invoked once when chain execution finishes.
	Finally(fn func(ctx context.Context, st ChainState) error) ChainBuilder
	// Dispatch creates and starts the chain workflow.
	Dispatch(ctx context.Context) (string, error)
}

ChainBuilder configures and dispatches a sequential workflow.

type ChainNode

type ChainNode struct {
	NodeID string
	Job    StoredJob
}

ChainNode binds a stable node identifier to its serialized job.

type ChainRecord

type ChainRecord struct {
	ChainID    string
	DispatchID string
	Queue      string
	Nodes      []ChainNode
	CreatedAt  time.Time
	// contains filtered or unexported fields
}

ChainRecord contains the immutable data required to create a chain.

func (ChainRecord) Continuations

func (r ChainRecord) Continuations() []ContinuationDefinition

Continuations returns an isolated named hook catalog from accepted chain input.

type ChainState

type ChainState struct {
	ChainID    string
	DispatchID string
	Queue      string
	Nodes      []ChainNode
	NextIndex  int
	Completed  bool
	Failed     bool
	Failure    string
	CreatedAt  time.Time
	UpdatedAt  time.Time
}

ChainState is the persisted execution view of a chain.

type Context

type Context struct {
	SchemaVersion int
	DispatchID    string
	JobID         string
	ChainID       string
	BatchID       string
	Attempt       int
	JobType       string
	// contains filtered or unexported fields
}

Context carries workflow correlation and isolated payload data into handlers and middleware.

func NewContext

func NewContext(schemaVersion int, dispatchID, jobID, chainID, batchID string, attempt int, jobType string, payload []byte) Context

NewContext reconstructs an engine message from correlation metadata and raw payload bytes. The payload is copied because compatibility adapters may reuse their input buffers.

func (Context) Bind

func (c Context) Bind(dst any) error

Bind unmarshals the job payload into dst.

func (Context) Continuation

func (c Context) Continuation() (busruntime.Continuation, bool)

Continuation returns an isolated value describing the immutable durable invocation.

func (Context) PayloadBytes

func (c Context) PayloadBytes() []byte

PayloadBytes returns a copy of raw job payload bytes.

func (Context) WithContinuation

func (c Context) WithContinuation(value busruntime.Continuation) Context

WithContinuation preserves a durable invocation through middleware model conversion.

type ContinuationBinder

type ContinuationBinder interface {
	BindContinuations([]ContinuationDefinition) (any, error)
}

ContinuationBinder snapshots a configured builder without extending public builder interfaces.

type ContinuationClaim

type ContinuationClaim = continuationClaim

ContinuationClaim exposes the internal recovery capability to root-owned adapters and fakes.

type ContinuationDefinition

type ContinuationDefinition struct {
	Phase string
	Job   StoredJob
}

ContinuationDefinition binds one named application job to a durable trigger phase.

type ContinuationReader

type ContinuationReader interface {
	FindContinuations(context.Context, string) ([]busruntime.ContinuationOutcome, error)
}

ContinuationReader returns triggered durable invocations rather than untriggered definitions.

type ContinuationStore

type ContinuationStore interface {
	PrepareContinuations(context.Context) error
	ContinuationOutcomes(context.Context, string) ([]busruntime.ContinuationOutcome, error)
	ClaimContinuation(context.Context, string, string, time.Time, time.Duration) (continuationClaim, bool, error)
	ValidateContinuation(context.Context, continuationClaim) (bool, error)
	SettleContinuation(context.Context, continuationClaim, string, time.Time) error
	BeginContinuation(context.Context, continuationClaim, string, time.Time) (continuationClaim, bool, error)
	RenewContinuation(context.Context, continuationClaim, time.Time) error
}

ContinuationStore adds atomic intent persistence without changing Store.

type CoordinatorLifecycle

type CoordinatorLifecycle interface {
	StartCoordinator(context.Context) error
	StopCoordinator(context.Context) error
	CoordinatorDone() <-chan struct{}
	CoordinatorError() error
}

CoordinatorLifecycle lets the shared runtime host recovery without another worker owner.

type DispatchResult

type DispatchResult struct {
	DispatchID string
}

DispatchResult identifies an accepted logical dispatch.

type Engine

type Engine interface {
	// Chain creates a sequential workflow builder.
	Chain(jobs ...Job) ChainBuilder
	// Batch creates an aggregate workflow builder.
	Batch(jobs ...Job) BatchBuilder
	// FindBatch returns persisted aggregate workflow state.
	FindBatch(ctx context.Context, batchID string) (BatchState, error)
	// FindChain returns persisted sequential workflow state.
	FindChain(ctx context.Context, chainID string) (ChainState, error)
	// Prune removes terminal workflow state older than before.
	Prune(ctx context.Context, before time.Time) error
}

Engine owns portable coordination and state, independently of ordinary delivery.

func NewCoordinator

func NewCoordinator(jobs *Jobs, opts ...Option) Engine

NewCoordinator attaches built-in workflow deliveries to an existing shared executor. It never registers ordinary handlers or starts or shuts down physical workers.

type Event

type Event struct {
	SchemaVersion int
	EventID       string
	Kind          EventKind
	DispatchID    string
	JobID         string
	ChainID       string
	BatchID       string
	Attempt       int
	JobType       string
	JobKey        string
	Queue         string
	Duration      time.Duration
	Time          time.Time
	Err           error
}

Event carries internal workflow facts and correlation into public observer adapters.

type EventKind

type EventKind string

EventKind identifies one workflow lifecycle fact.

const (
	// EventDispatchStarted marks the beginning of logical dispatch submission.
	EventDispatchStarted EventKind = "dispatch_started"
	// EventDispatchSucceeded records that a logical dispatch was accepted.
	EventDispatchSucceeded EventKind = "dispatch_succeeded"
	// EventDispatchFailed records that a logical dispatch was rejected.
	EventDispatchFailed EventKind = "dispatch_failed"
	// EventJobStarted records the beginning of a logical handler attempt.
	EventJobStarted EventKind = "job_started"
	// EventJobSucceeded records a committed logical job success.
	EventJobSucceeded EventKind = "job_succeeded"
	// EventJobFailed records a permanent or exhausted logical job failure.
	EventJobFailed EventKind = "job_failed"
	// EventChainStarted records creation and initial scheduling of a chain.
	EventChainStarted EventKind = "chain_started"
	// EventChainAdvanced records a committed transition to the next chain node.
	EventChainAdvanced EventKind = "chain_advanced"
	// EventChainCompleted records terminal chain success.
	EventChainCompleted EventKind = "chain_completed"
	// EventChainFailed records terminal chain failure.
	EventChainFailed EventKind = "chain_failed"
	// EventBatchStarted records creation and initial scheduling of a batch.
	EventBatchStarted EventKind = "batch_started"
	// EventBatchProgressed records a committed change to aggregate batch state.
	EventBatchProgressed EventKind = "batch_progressed"
	// EventBatchCompleted records terminal batch completion.
	EventBatchCompleted EventKind = "batch_completed"
	// EventBatchFailed records a logical batch failure.
	EventBatchFailed EventKind = "batch_failed"
	// EventBatchCancelled records cancellation after a batch can no longer continue.
	EventBatchCancelled EventKind = "batch_cancelled"
	// EventCallbackStarted records the beginning of an ephemeral callback attempt.
	EventCallbackStarted EventKind = "callback_started"
	// EventCallbackSucceeded records successful callback completion.
	EventCallbackSucceeded EventKind = "callback_succeeded"
	// EventCallbackFailed records callback failure.
	EventCallbackFailed EventKind = "callback_failed"
)

type Handler

type Handler func(ctx context.Context, j Context) error

Handler processes one logical workflow delivery.

type Job

type Job struct {
	Type    string
	Payload any
	Options JobOptions
}

Job describes one logical application job and its workflow delivery policy.

func NewJob

func NewJob(jobType string, payload any) Job

NewJob creates a typed workflow job payload with optional fluent policy.

func (Job) Backoff

func (j Job) Backoff(backoff time.Duration) Job

Backoff sets retry backoff for this job.

func (Job) Delay

func (j Job) Delay(delay time.Duration) Job

Delay defers job execution.

func (Job) OnQueue

func (j Job) OnQueue(name string) Job

OnQueue sets the target queue for this job.

func (Job) Retry

func (j Job) Retry(max int) Job

Retry sets max retry attempts for this job.

func (Job) Timeout

func (j Job) Timeout(timeout time.Duration) Job

Timeout sets execution timeout for this job.

func (Job) UniqueFor

func (j Job) UniqueFor(ttl time.Duration) Job

UniqueFor sets dedupe TTL for this job.

type JobConfig

type JobConfig struct {
	TranslateError func(error) error
	PanicError     func(any) error
	Clock          func() time.Time
	Observer       Observer
	Middlewares    []Middleware
}

JobConfig supplies execution policy independently of a workflow coordinator.

type JobOptions

type JobOptions struct {
	Queue     string
	Delay     time.Duration
	Timeout   time.Duration
	Retry     int
	Backoff   time.Duration
	UniqueFor time.Duration
}

JobOptions carries queue delivery policy through the versioned workflow envelope.

type Jobs

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

Jobs owns ordinary delivery and the executor shared by portable coordinators. Constructing it does not allocate workflow state or install chain/batch routes.

func NewJobs

func NewJobs(q any, cfg JobConfig) (*Jobs, error)

NewJobs installs only the retained ordinary envelope route; canonical routes are installed as logical handlers register, independently of coordination.

func (*Jobs) Dispatch

func (r *Jobs) Dispatch(ctx context.Context, job Job) (DispatchResult, error)

Dispatch enqueues one job for execution.

func (*Jobs) DispatchDirect

func (r *Jobs) DispatchDirect(ctx context.Context, job StoredJob) (DispatchResult, error)

DispatchDirect enqueues one ordinary job using its application type and payload.

func (*Jobs) ExecuteDirect

func (r *Jobs) ExecuteDirect(ctx context.Context, job StoredJob, metadata busruntime.DeliveryMetadata, attempt busruntime.DeliveryAttempt) error

ExecuteDirect shares missing-handler execution and facts with driver-owned generic activity wrappers.

func (*Jobs) Register

func (r *Jobs) Register(jobType string, handler Handler)

Register binds a job type to a handler.

func (*Jobs) Shutdown

func (r *Jobs) Shutdown(ctx context.Context) error

Shutdown stops the underlying queue worker runtime.

func (*Jobs) StartWorkers

func (r *Jobs) StartWorkers(ctx context.Context) error

StartWorkers starts the underlying queue worker runtime.

type Middleware

type Middleware interface {
	// Handle wraps the remaining middleware and handler chain.
	Handle(ctx context.Context, jc Context, next Next) error
}

Middleware can intercept logical workflow job execution.

type Next

type Next func(ctx context.Context, jc Context) error

Next represents the remaining middleware and handler execution chain.

type Observer

type Observer interface {
	// Observe consumes one best-effort workflow fact.
	Observe(ctx context.Context, event Event)
}

Observer receives internal workflow events.

func MultiObserver

func MultiObserver(observers ...Observer) Observer

MultiObserver fans out one event to multiple observers.

type ObserverFunc

type ObserverFunc func(ctx context.Context, event Event)

ObserverFunc adapts a function to Observer.

func (ObserverFunc) Observe

func (f ObserverFunc) Observe(ctx context.Context, event Event)

Observe calls the wrapped observer function.

type Option

type Option func(*runtime)

Option configures one workflow runtime before its internal handlers are registered.

func WithClock

func WithClock(clock func() time.Time) Option

WithClock overrides the runtime clock used for event/state timestamps.

func WithContinuationQueue

func WithContinuationQueue(queue string) Option

WithContinuationQueue resolves default hook routing into immutable initial definitions.

func WithContinuationResource

func WithContinuationResource(resource string) Option

WithContinuationResource scopes competing recovery runners to one physical queue resource.

func WithMiddleware

func WithMiddleware(middlewares ...Middleware) Option

WithMiddleware appends middleware to the runtime execution chain.

func WithObserver

func WithObserver(observer Observer) Option

WithObserver installs an event observer for workflow lifecycle facts.

func WithStore

func WithStore(store Store) Option

WithStore overrides the orchestration store used for chain/batch/callback state.

func WithoutEphemeralCallbacks

func WithoutEphemeralCallbacks() Option

WithoutEphemeralCallbacks disables process-local callback retention for recording runtimes that never execute workflow deliveries.

type ResolvedDelivery

type ResolvedDelivery struct {
	// JobType is the logical application type when a supported envelope provides one, otherwise the physical type.
	JobType string
	// Payload is the logical application payload when a supported envelope provides one, otherwise the physical payload.
	Payload []byte
	// DispatchID correlates deliveries created by the same application dispatch.
	DispatchID string
	// JobID identifies the logical workflow job represented by this delivery.
	JobID string
	// ChainID identifies the owning chain when the delivery belongs to one.
	ChainID string
	// BatchID identifies the owning batch when the delivery belongs to one.
	BatchID string
}

ResolvedDelivery contains the logical application identity and workflow correlation recovered from a physical workflow delivery.

func ResolveDelivery

func ResolveDelivery(deliveryType string, payload []byte) ResolvedDelivery

ResolveDelivery decodes the owned protocol while preserving physical identity for unsupported or malformed input.

type Runtime

type Runtime interface {
	Engine
	// Register binds a logical job type to its handler.
	Register(jobType string, handler Handler)
	// Dispatch submits a legacy envelope delivery.
	Dispatch(ctx context.Context, job Job) (DispatchResult, error)
	// DispatchDirect submits a canonical ordinary delivery.
	DispatchDirect(ctx context.Context, job StoredJob) (DispatchResult, error)
	// StartWorkers starts the selected physical runtime.
	StartWorkers(ctx context.Context) error
	// Shutdown drains the selected physical runtime.
	Shutdown(ctx context.Context) error
}

Runtime composes the built-in coordinator and job runtime for internal compatibility callers. The public Queue constructs and holds these responsibilities separately.

func New

func New(q any, opts ...Option) (Runtime, error)

New creates a workflow engine using an in-memory orchestration store.

func NewWithStore

func NewWithStore(q any, store Store, opts ...Option) (Runtime, error)

NewWithStore creates a workflow engine with a custom orchestration store.

type SQLStoreConfig

type SQLStoreConfig struct {
	DB         *sql.DB
	DriverName string
	DSN        string
	// AutoMigrate is retained for compatibility with the established config
	// shape. NewSQLStore keeps startup schema creation enabled by default; use
	// NewSQLStoreWithManagedSchema when deployment tooling owns the schema.
	AutoMigrate bool
}

SQLStoreConfig configures connection ownership, dialect binding, and schema setup for a SQL store.

type Store

type Store interface {
	// CreateChain persists a newly accepted chain.
	CreateChain(ctx context.Context, rec ChainRecord) error
	// AdvanceChain atomically claims completedNode and returns the current successor.
	// Repeating the same (chainID, completedNode) claim must not advance again.
	// When done is true, GetChain must immediately expose Completed or Failed state.
	AdvanceChain(ctx context.Context, chainID string, completedNode string) (next *ChainNode, done bool, err error)
	// FailChain commits terminal failure without replacing completed state.
	FailChain(ctx context.Context, chainID string, cause error) error
	// GetChain returns current chain state.
	GetChain(ctx context.Context, chainID string) (ChainState, error)

	// CreateBatch persists a newly accepted batch.
	CreateBatch(ctx context.Context, rec BatchRecord) error
	// MarkBatchJobStarted records that one batch member began execution.
	MarkBatchJobStarted(ctx context.Context, batchID, jobID string) error
	// MarkBatchJobSucceeded commits the first outcome for (batchID, jobID).
	// Duplicate outcomes must return current state without changing counters.
	MarkBatchJobSucceeded(ctx context.Context, batchID, jobID string) (BatchState, bool, error)
	// MarkBatchJobFailed commits the first outcome for (batchID, jobID).
	// Duplicate outcomes must return current state without changing counters.
	MarkBatchJobFailed(ctx context.Context, batchID, jobID string, cause error) (BatchState, bool, error)
	// CancelBatch commits aggregate batch cancellation.
	CancelBatch(ctx context.Context, batchID string) error
	// GetBatch returns current batch state.
	GetBatch(ctx context.Context, batchID string) (BatchState, error)

	// MarkCallbackInvoked atomically claims one callback idempotency key.
	MarkCallbackInvoked(ctx context.Context, key string) (bool, error)
	// Prune removes terminal workflow state older than before.
	Prune(ctx context.Context, before time.Time) error
}

Store defines the compatibility state transitions required by chain, batch, and callback orchestration; built-ins also implement outcomeStore.

func NewMemoryStore

func NewMemoryStore() Store

NewMemoryStore creates an in-memory orchestration store implementation.

func NewSQLStore

func NewSQLStore(cfg SQLStoreConfig) (Store, error)

NewSQLStore creates a SQL-backed orchestration store.

func NewSQLStoreWithManagedSchema

func NewSQLStoreWithManagedSchema(cfg SQLStoreConfig) (Store, error)

NewSQLStoreWithManagedSchema creates a SQL-backed orchestration store that executes no schema DDL because deployment tooling owns the required tables.

type StoredJob

type StoredJob struct {
	Type    string     `json:"type"`
	Payload []byte     `json:"payload"`
	Options JobOptions `json:"options"`
}

StoredJob is the version-one logical job representation embedded in workflow state and delivery envelopes.

Jump to

Keyboard shortcuts

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