Documentation
¶
Overview ¶
Package workflow - DAG workflow engine layered on the task engine
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Client ¶
type Client interface {
/*
DefineWorkflow define (but do NOT start) a workflow.
The workflow row (born PENDING) and its step rows (born DEFINED) are written in a database
transaction; the scheduler is NOT poked. The caller is responsible for calling
SubmitWorkflow afterwards to actually start it. This split lets a caller commit its own
additional state between the define and the submit (state-before-poke). Before any DB write
the workflow spec is validated as a DAG and every step Type is checked against the client's
registered step-type set. On error, inspect the returned error with `errors.As`: a
`models.PersistenceError` means the database operation failed and no workflow was created; a
`goutils.ValidationError`/`BadInputError` means the spec (or an unknown step Type) was
rejected before any DB work.
@param ctx context.Context - execution context
@param params DefineWorkflowParams - the workflow definition parameters
@param activeDBClient db.Database - an existing open database transaction to continue in
@return the newly defined workflow entry
*/
DefineWorkflow(
ctx context.Context, params DefineWorkflowParams, activeDBClient db.Database,
) (models.Workflow, error)
/*
SubmitWorkflow start an already-defined workflow by poking the scheduler.
This is the submit-only half of DefineAndRunWorkflow: it emits a Process Workflow event for
a workflow whose rows have already been persisted (via DefineWorkflow). It runs no database
work. A failed submit `errors.As` a `models.IPCMessageQueueError`: the workflow rows still
exist and the scheduler's maintenance sweep will eventually drive the still-PENDING workflow,
so a caller following state-before-poke may treat a submit failure as a lost poke rather than
a lost workflow.
@param ctx context.Context - execution context
@param workflowID string - ID of the already-defined workflow to start
*/
SubmitWorkflow(ctx context.Context, workflowID string) error
/*
DefineAndRunWorkflow define and start a workflow.
The combined convenience wrapper: it calls DefineWorkflow, then SubmitWorkflow. The submit
happens after the rows are persisted and is not part of that transaction. On error, inspect
the returned error with `errors.As`: a `models.PersistenceError` means the database operation
failed and no workflow was created; a `models.IPCMessageQueueError` means the workflow was
created but could not be submitted to the scheduler (the returned entry is still valid).
@param ctx context.Context - execution context
@param params DefineWorkflowParams - the workflow definition parameters
@param activeDBClient db.Database - an existing open database transaction to continue in
@return the newly defined workflow entry
*/
DefineAndRunWorkflow(
ctx context.Context, params DefineWorkflowParams, activeDBClient db.Database,
) (models.Workflow, error)
/*
ReviveWorkflow request the scheduler revive a FAILED / TIMED_OUT workflow.
The workflow is read in a database transaction to confirm it exists, then a Revive Failed
Workflow event is emitted. The client does NOT check the workflow state or the newDeadline
rule ("required iff TIMED_OUT") - the scheduler's revive handler owns those against live
state, preserving the single-writer invariant. On error, inspect the returned error with
`errors.As`: a `models.PersistenceError` means the workflow could not be read; a
`models.IPCMessageQueueError` means the revive request could not be submitted to the
scheduler.
@param ctx context.Context - execution context
@param workflowID string - ID of the workflow to revive
@param newDeadline *time.Time - optional new workflow deadline (required by the scheduler
for a TIMED_OUT workflow)
@param activeDBClient db.Database - an existing open database transaction to continue in
*/
ReviveWorkflow(
ctx context.Context, workflowID string, newDeadline *time.Time, activeDBClient db.Database,
) error
/*
CancelWorkflow request the scheduler cancel a workflow.
The workflow is read in a database transaction to confirm it exists, then a Cancel Workflow
event is emitted. On error, inspect the returned error with `errors.As`: a
`models.PersistenceError` means the workflow could not be read; a
`models.IPCMessageQueueError` means the cancel request could not be submitted to the
scheduler.
@param ctx context.Context - execution context
@param workflowID string - ID of the workflow to cancel
@param activeDBClient db.Database - an existing open database transaction to continue in
*/
CancelWorkflow(ctx context.Context, workflowID string, activeDBClient db.Database) error
/*
ListWorkflows list workflows belonging to this client's creator.
The query is creator-scoped (see the Client doc): when `filters.Creators` is empty it is
filled in with the client's DefaultCreator; when the caller sets it explicitly that set is
used verbatim. A client with neither a DefaultCreator nor an explicit `filters.Creators` has
no scope to apply and the call is rejected with a `goutils.BadInputError` rather than
silently listing every creator's workflows. A failed read `errors.As` a
`models.PersistenceError`.
@param ctx context.Context - execution context
@param filters db.WorkflowQueryFilter - query filtering conditions
@param activeDBClient db.Database - an existing open database transaction to continue in
@return the matching workflow entries
*/
ListWorkflows(
ctx context.Context, filters db.WorkflowQueryFilter, activeDBClient db.Database,
) ([]models.Workflow, error)
/*
GetWorkflow fetch one workflow.
Creator-scoped (see the Client doc): a workflow belonging to another creator `errors.As` a
`goutils.NotFoundError`, indistinguishable from a workflow which does not exist. Any other
read failure `errors.As` a `models.PersistenceError`.
@param ctx context.Context - execution context
@param workflowID string - workflow ID
@param activeDBClient db.Database - an existing open database transaction to continue in
@return the workflow entry
*/
GetWorkflow(
ctx context.Context, workflowID string, activeDBClient db.Database,
) (models.Workflow, error)
/*
ListWorkflowSteps list the steps of a workflow.
The parent workflow is read first and creator-scoped, so a workflow belonging to another
creator `errors.As` a `goutils.NotFoundError` and its steps are never returned. The steps
come back topologically sorted (alphabetical among steps at the same depth), the order the
persistence layer defines.
@param ctx context.Context - execution context
@param workflowID string - the parent workflow ID
@param activeDBClient db.Database - an existing open database transaction to continue in
@return the workflow's steps
*/
ListWorkflowSteps(
ctx context.Context, workflowID string, activeDBClient db.Database,
) ([]models.WorkflowStep, error)
/*
GetWorkflowStep fetch one workflow step along with how it was executed.
Creator-scoped against the step's own creator (see the Client doc): a step belonging to
another creator `errors.As` a `goutils.NotFoundError`, and nothing about its execution is
read. Any other read failure `errors.As` a `models.PersistenceError`.
The returned history holds one entry per task which ran the step - its first run plus one
per user-initiated revive - each carrying that task's own execution attempts. Ownership of
the step is what authorizes reading those tasks, which belong to the engine's reserved
creator and are therefore invisible to an application's own task.Client. Entries are ordered
newest task first, so `[0]` is the most recent attempt; each entry's executions are ordered
oldest first. A step which has never been dispatched yields an empty history.
@param ctx context.Context - execution context
@param stepID string - workflow step ID
@param activeDBClient db.Database - an existing open database transaction to continue in
@return the workflow step entry, and its execution history
*/
GetWorkflowStep(
ctx context.Context, stepID string, activeDBClient db.Database,
) (models.WorkflowStep, []models.WorkflowStepExecution, error)
/*
DeleteWorkflow delete a workflow and reap the tasks that executed its steps.
Creator-scoped (see the Client doc). Only a terminal workflow (COMPLETE / CANCELLED) may be
deleted; a live one must be cancelled first, and the refusal `errors.As` a
`goutils.ConsistencyError`. A workflow belonging to another creator `errors.As` a
`goutils.NotFoundError` - reported before its state is ever considered. Deleting a workflow
cascades away its steps and reaps the tasks (and task execution history) which ran them.
@param ctx context.Context - execution context
@param workflowID string - workflow ID
@param activeDBClient db.Database - an existing open database transaction to continue in
*/
DeleteWorkflow(ctx context.Context, workflowID string, activeDBClient db.Database) error
}
Client workflow engine client - the user-facing submission / user-mutation API. Every submission operation is "write DB rows (definition only), then poke the scheduler": the Client never performs a workflow state transition (the scheduler is the single writer of live state), it only writes the initial DEFINED/PENDING definition rows and enqueues scheduler events. Alongside those it serves the workflow-facing reads and deletes, which touch no scheduler state at all. See workflow/DESIGN.md "Workflow Client". Mirrors the task engine's task.Client, including the define / submit / define-and-run split.
Creator scoping ¶
Every read and delete on this interface is scoped to the client's creator: the per-call override where one is offered, otherwise the client's DefaultCreator. A workflow (or step) belonging to another creator is reported as not-found rather than as a permission failure, so the client never discloses the existence of one it does not own. `db.Database` remains the unscoped escape hatch for an application that genuinely needs to see across creators.
GetWorkflowStep is the one deliberate reach outside that scope: it returns the tasks which executed a step, and those always carry the engine's reserved models.WorkflowExecutionTaskCreator. Owning the step is what authorizes reading them, so an application never needs a task.Client built under the engine's own creator to find out how its step was processed.
type DefineWorkflowParams ¶
type DefineWorkflowParams struct {
// Spec the workflow specification (name, deadline, metadata, and the DAG of steps).
Spec models.NewWorkflowParameter `validate:"required"`
// Creator optional per-workflow creator override; nil uses the client's DefaultCreator. The
// resolved value must be non-empty or the define fails validation downstream (the Workflow
// entry's Creator is `validate:"required"`).
Creator *string
}
DefineWorkflowParams the per-workflow parameters for the workflow definition entry points. It carries the workflow spec and an optional creator override.
type NewClientParams ¶
type NewClientParams struct {
// Name of the client - also the IPC sender identity stamped on scheduler pokes.
Name string `validate:"required"`
// DefaultCreator opaque creator identity stamped on workflows submitted through this client when
// the define call does not provide a per-workflow override. tasking never interprets it; it is
// the routing key for the workflow's audit events and notifications.
DefaultCreator string
// Persistence persistence client
Persistence db.Client `validate:"required"`
// Config workflow client config
Config models.WorkflowClientConfig `validate:"required"`
// Redis REDIS client
Redis goutilsRedis.Client `validate:"required"`
// IPCSenderFactory factory function to define Redis based IPC message senders
IPCSenderFactory task.IPCMsgSenderFactoryCB `validate:"required"`
// KnownStepTypes the set of step Types with a registered handler (the same registration the Step
// Runner holds). DefineWorkflow rejects, up front, a workflow containing a step whose Type is not
// in this set - a fail-fast validation far friendlier than a mid-run failure. Must be non-empty.
KnownStepTypes map[string]bool `validate:"required,gt=0"`
}
NewClientParams init parameters for a workflow client
type NewWorkflowSchedulerParams ¶
type NewWorkflowSchedulerParams struct {
// Persistence persistence client
Persistence db.Client `validate:"required"`
// TaskClient task engine client, used to dispatch (and later cancel) step execution tasks
TaskClient task.Client `validate:"required"`
// Config workflow scheduler config
Config models.WorkflowSchedulerConfig `validate:"required"`
// Redis REDIS client
Redis goutilsRedis.Client `validate:"required"`
// IPCReceiverFactory factory function to define Redis based IPC message receivers
IPCReceiverFactory task.IPCMsgReceiverFactoryCB `validate:"required"`
// IPCSenderFactory factory function to define Redis based IPC message senders
IPCSenderFactory task.IPCMsgSenderFactoryCB `validate:"required"`
// NotifyConsumerFactory factory function to define the notification consumer the scheduler
// subscribes task-engine feedback with. Neither this factory nor Redis is retained after
// construction - the resulting Consumer is.
NotifyConsumerFactory NotifyConsumerFactoryCB `validate:"required"`
// OnFatal, when set, is invoked (at most once) when the processing goroutine hits an
// unrecoverable fault instead of terminating the process. reporter identifies the faulting
// thread; err carries the cause (with code position in its chain); timestamp is when it was
// detected. When nil, the default logs and calls log.Fatal, preserving prior behavior. The
// goroutine exits after the callback runs.
OnFatal models.OnFatalCB
}
NewWorkflowSchedulerParams init parameters for a workflow scheduler
type NotifyConsumerFactoryCB ¶
type NotifyConsumerFactoryCB func( parentCtx context.Context, params notify.NewConsumerParams, ) (notify.Consumer, error)
NotifyConsumerFactoryCB factory function signature for defining the scheduler's notification consumer. Defaults to notify.NewConsumer; overridable for tests.
type RunWorkflowStepTaskProcessor ¶
type RunWorkflowStepTaskProcessor struct {
goutils.Component
// contains filtered or unexported fields
}
RunWorkflowStepTaskProcessor the Step Runner: the single models.TaskExecutionProcessor the workflow engine registers with the task engine under models.WorkflowExecutionTaskName (__EXECUTE_WORKFLOW_STEP__). Every workflow step, regardless of its Type, runs as a task of that one name executed by this one processor. The Runner loads the step referenced by the task's Parameters, derives its parent workflow, and dispatches to the WorkflowStepProcessor registered for the step's Type. See workflow/DESIGN.md "Step Execution".
func NewRunWorkflowStepTaskProcessor ¶
func NewRunWorkflowStepTaskProcessor( persistence db.Client, handlers map[string]models.WorkflowStepProcessor, ) (*RunWorkflowStepTaskProcessor, error)
NewRunWorkflowStepTaskProcessor define a new workflow Step Runner.
@param persistence db.Client - persistence client
@param handlers map[string]models.WorkflowStepProcessor - step Type to processor mapping this
Runner supports. Fixed at construction; must contain no nil processors.
@returns new Step Runner
func (*RunWorkflowStepTaskProcessor) ProcessTaskExecution ¶
func (r *RunWorkflowStepTaskProcessor) ProcessTaskExecution( ctx context.Context, taskEntry models.Task, _ models.TaskExecution, ) error
ProcessTaskExecution execute one workflow step. This implements models.TaskExecutionProcessor; its return value becomes the task's terminal state. The Runner never reports to the workflow scheduler - feedback flows entirely through the notify path.
@param ctx context.Context - execution context
@param taskEntry models.Task - the __EXECUTE_WORKFLOW_STEP__ task, whose Parameters carry the
workflow step ID
@param executeEntry models.TaskExecution - the task execution instance (unused: the Runner
keys entirely off the task Parameters)
type Scheduler ¶
type Scheduler interface {
/*
Start the scheduler processing units
@param ctx context.Context - execution context
*/
Start(ctx context.Context) error
/*
Stop the workflow scheduler processing units
@param ctx context.Context - execution context
*/
Stop(ctx context.Context) error
}
Scheduler workflow scheduler: the single point of truth and the only mutator of workflow / step state. See workflow/DESIGN.md "Workflow Scheduler".
func NewWorkflowScheduler ¶
func NewWorkflowScheduler( parentCtx context.Context, params NewWorkflowSchedulerParams, ) (Scheduler, error)
NewWorkflowScheduler define a new workflow scheduler
@param parentCtx context.Context - the parent execution context @param params NewWorkflowSchedulerParams - parameters of the workflow scheduler @returns new workflow scheduler