Identity

Table of Contents

This page defines the workflow Identity: the engine's own fixture, and the reference implementation of the step protocol. It runs the steps its request declares and reports the outcome each one asks for, so a caller exercises a completion, a completion with warnings, a failure, a compensation, a slow step and a long run from the shell, with no domain data and no other component. A run leaves the workflow instance and its steps behind, and changes no record of another component. Recovery is the engine's own path: a completed step that declared a compensation is unwound when a later step fails, and a failed step carries its error and its log to the progress read.

1. Purpose

The identity workflow exists to exercise the engine. It makes every path the engine supports reachable from the shell with no other component: a start and a dispatch, a step that completes, a step that completes with warnings, a step that fails, a run that compensates its completed steps, a step that waits so a run can be observed in flight, and a run of many steps. When it finishes, the workflow instance and its steps are the whole of what exists, and the progress read reports what happened.

The fixture is also the worked reference for the step protocol. Its step handler takes the step context from the message headers and reports its outcome through the same completion path a domain step uses, so a reader sees the contract implemented rather than described.

2. Participants

The caller starts a run from the shell, declaring the steps and the outcome each one reports, then follows the run. The workflow service owns the definition and serves both step subjects itself, because the fixture's work is the engine's rather than a domain component's. The process manager builds the step list from the request, dispatches one step at a time, records each outcome, and settles the run. The store holds the run, its steps, their results, errors and logs.

Participant Kind Responsibility
Caller role Starts a run from the shell, declaring the steps and the outcome each one reports, and follows it
Workflow service component Owns the definition and serves both step subjects
Process manager component Builds the step list, dispatches each step, records each outcome, and settles the run
Store store Holds the run, its steps, their results, errors and logs
Client component Follows the run through the progress read

3. Messages

One subject dispatches every step, because the payload rather than the subject says what a step does. A step is addressed by its name, so a later step reads an earlier step's result by name.

Message Subject Objective
Start message workflow.v1.ops.start_workflow Opens the run with the type identity_workflow and the request that lists the steps
Step command workflow.v1.identity.step Dispatches one declared step to the fixture's own handler
Compensation command workflow.v1.identity.compensate Dispatches the compensation of a completed step that declared one
Step completion workflow.v1.ops.step_completed Reports the outcome the request asked for: completed, completed with warnings, or failed
Progress read workflow.v1.ops.get_workflow_steps Returns the run's status and one summary per declared step
Retry action workflow.v1.ops.retry_workflow_instance Resumes a stopped run from its failed step

The fields the request carries, and the fields of a step within it:

identity_step_request.png

Figure 1: The fixture's request: the steps to run, each naming the outcome it should report, whether it declares a compensation, and how long it should wait before it reports.

The fields of the step command and of the completion a step reports:

workflow_step_command.png

Figure 2: The fields a step command carries: the step identifier, the instance identifier, the tenant, and the payload the operation performs.

workflow_step_completion.png

Figure 3: The fields a step completion carries: the step identifier it echoes, the outcome, the result, the error, and one log entry per item the step could not do cleanly.

4. Steps

Every step is one entry in the request, and its name is its identity. A step performs no domain work: it waits if the request asks it to, then reports the outcome the request declares.

Operation Produces On failure
Report completion The step marked completed, with the request echoed as its result Nothing; the run advances to the next step
Report warnings The step marked completed with warnings, with one log entry Nothing; the run advances
Report failure The step marked failed, with an error and a log entry The engine compensates the completed steps that declared a compensation
Wait, then report The outcome its behaviour declares, after the stated delay The delay does not change the failure rule
Declare a compensation A compensation subject on the step The step is unwound when a later failure compensates the run

A behaviour the request does not recognise fails the step rather than passing for a completion, so a mistyped request is visible in the run rather than silently succeeding.

5. Interaction

The diagram draws one run: the caller starting it, the process manager dispatching each declared step to the fixture's own handler, the handler reporting the outcome the request asked for, the compensation path when a step fails, and the client reading progress.

identity_workflow_interaction.png

Figure 4: Identity: the caller starts a run declaring its steps, the process manager dispatches each one to the fixture's handler, the handler reports the declared outcome, a failure compensates the completed steps that declared a compensation, and the client follows the run through the progress read.

Source: identity_workflow_interaction.puml. Regenerate with plantuml -tpng doc/knowledge/workflows/identity_workflow_interaction.puml.

6. Failure and recovery

The definition declares the compensate policy, because the fixture's completed steps are its own records and nothing a person expects to keep. What a failing run unwinds is decided by the compensation subjects the request declares: a completed step that declared one is compensated at a negative step index when a later step fails, and a completed step that declared none has nothing to undo, so the failure stands on the failing step with its error and its log.

A retry resumes a failed run at its failed step, under the same step identity, and the completed steps keep their results. The fixture's steps do no domain work, so a retry leaves no data to repair; its value is as a rehearsal of the engine's own path. The policies themselves live in failure, compensation and retry.

7. Progress

The fixture adds nothing to the platform's progress read. A client follows the run through workflow.v1.ops.get_workflow_steps and renders one line per declared step, with the step's state and its error. The states a run occupies are pending, in progress, completed, completed with warnings, compensated and failed, and a client must be ready to display each of them, because the fixture can reach all of them from a request.

8. Patterns used

  • Saga — the fixture compensates the steps that declared a compensation.
  • Process Manager — the engine runs the steps the request declares.

9. Related

10. See also

Emacs 29.3 (Org mode 9.6.15)