Reference
Everything FlowChassis 0.1.0 offers, in one page. The package documentation is on pkg.go.dev, and the exact rules are in the contract.
The Engine
| Call | What it does |
|---|---|
Open(path, Options) |
Opens or creates the journal file and locks it against other processes |
New(store, Options) |
The same over any Store. NewMemStore keeps the journal in memory, for tests |
Register(Flow) |
Adds a flow. Runs of it already in the journal start or resume |
Start(flow, id, input) |
Starts a run. An empty id gets a random one. The same id with the same flow and input returns the existing run; with anything else, ErrConflict |
Wait(ctx, id) |
Blocks until the run finishes, and returns it |
Get(id) |
One run, as a RunInfo |
List() |
Every run, in the order they started |
Cancel(id) |
Stops a run and undoes its completed steps |
Compact(before) |
Rewrites the journal with one record per run, leaving out runs that finished before before |
Close() |
Stops the engine. A step interrupted by Close runs again on the next open |
Err() |
Why the engine stopped, if a journal write failed |
Options has three fields: Workers, the number of runs that execute at once (default 4); Retry, the policy for steps that don’t set one; and Now, a clock for tests.
Flows and Steps
A Flow is a Name and a list of Steps. A run goes from each step to the one after it, unless a step chooses another with Ctx.Next. It completes after its last step.
| Step field | What it does |
|---|---|
Name |
Identifies the step in the journal. Unfinished runs resume by it, so keep it stable |
Do |
Performs the step. Returning nil completes it and saves its state changes. An error throws them away and retries |
Undo |
Reverses the step during compensation, seeing the state as the step left it. Nil means nothing to undo |
Retry |
A RetryPolicy for this step’s Do and Undo |
A RetryPolicy has MaxAttempts (the first attempt included), Backoff (the first wait), Multiplier and MaxBackoff (a cap). Fields left at zero come from Options.Retry, then from the default: 3 attempts, starting at 100 ms and doubling. A zero MaxBackoff means no cap. Attempts cut off by a crash count; attempts cut off by Close don’t. Wrap an error in flowchassis.Permanent to skip the retries.
Inside a Step
On *Ctx |
What it gives |
|---|---|
| the value itself | A context.Context, canceled by Cancel or Close |
Input() |
The run’s input |
Get, Set, Delete |
The run’s state: named byte values, kept only when the step completes |
Next(name) |
The step to go to next. Next("") ends the run as completed |
Key |
An idempotency key: run/step/seq, plus /undo in an undo. The same on every attempt and after a restart |
Attempt |
This attempt’s number, counted across restarts |
Run, Flow, Step, Seq, Undoing |
Where the step is |
Statuses
| Status | Meaning |
|---|---|
pending |
Started; no step has begun, or its flow isn’t registered in this process yet |
running |
A step is under way or about to begin |
retrying |
A step failed and waits for its next attempt; RetryAt says when |
compensating |
Undoing completed steps, newest first |
completed |
Every step finished |
compensated |
The run failed or was canceled, and every completed step with an Undo was undone |
failed |
An undo kept failing, so the run stopped part way through compensation and needs a person |
Errors
| Error | When |
|---|---|
ErrUnknownFlow |
Start names a flow that isn’t registered |
ErrConflict |
Start reuses a run ID with another flow or input |
ErrNotFound |
No run has that ID |
ErrFinished |
Cancel on a run that has ended |
ErrLocked |
Another process has the journal open |
ErrCorrupt |
The journal is damaged somewhere other than a torn final write |
ErrStopped |
A journal write failed, so the engine stopped running steps |
ErrClosed |
The engine was closed |
What a Crash Does
- During a step. The step runs again on the next start, attempt number one higher. Steps before it don’t. A step that crashes the process every time gives up at
MaxAttempts, and the run compensates. - During
Close. A step that returns an error because its context was canceled runs again on the next open, as the same attempt. A step that completes anyway is recorded. - During an undo. That undo runs again. Undos already done don’t.
- While a step waits to retry. The wait goes on from the time recorded in the journal.
- In the middle of a journal write. The torn record is cut off on open and kept in a
.tornfile beside the journal, and the run carries on from the record before it. A tear counts as one only if nothing whole follows it; damage anywhere else is refused withErrCorruptand the file is left as it was. - When the disk is full. The engine stops before the next step, writes nothing more, and resumes from the last good record once the journal opens again.
The Journal
One append-only file: an 8-byte header, then records, each a 4-byte length, a 4-byte CRC-32C checksum and a JSON object. Every record names its run and type: start, begin, done, fail, yield, cancel, comp, ubegin, udone, ufail, uyield, end, or snapshot and sstate after compaction. A run’s status, state and history follow from its records in order. The journal format has every field.
The Command-Line Tool
| Command | What it does |
|---|---|
flowchassis runs JOURNAL [-status S] [-json] |
Lists runs: status, current step, attempt, error |
flowchassis show JOURNAL RUN [-json] |
One run: input, state, and every record with its time |
flowchassis check JOURNAL |
Verifies every record’s checksum and counts runs by status. Exits 0 when good, 1 when damaged, 3 when it ends in a torn write |
flowchassis compact JOURNAL [-drop-finished-before D] |
Rewrites the journal with one record per run |
flowchassis demo |
The crash demo: worker processes killed mid-flow, then every order checked |
flowchassis version |
The version and journal format |
runs, show and check read the journal without locking it, so they work while a program has it open. compact takes the lock.
Limits
One process per journal, on one machine. Steps run at least once, not exactly once. A run’s input and each step’s state must fit in a 16 MB record. A finished run that Compact drops is forgotten, so its ID can be started again. There is no server, dashboard or graphical designer.