Fob
Browse the docs

Run steps locally

fob-worker steps run runs one of your steps on your machine, the way the worker would run it for the Orchestrator, without the Orchestrator. Run it from the root of your worker repo.

fob-worker steps list                      # what's under src/steps/
fob-worker steps run IN1_01_check          # asks which config to use

Choosing a config#

FlagConfig used
--station IN1The step's config in that station's file in .orchestrator/stations/
--scenario <name>A saved test config (below)
--empty{}, so inputSchema defaults apply
noneA menu of every station that uses the step, every scenario for it, and "No config"

With --station, the station file must be in your repo; run fob-orc stations pull IN1 first if it isn't.

Scenarios#

A scenario is a JSON file with a config for one step, kept for repeat runs: a typical case, an edge case, yesterday's bug.

.orchestrator/scenarios/<step slug>/<name>.json
mkdir -p .orchestrator/scenarios/IN1_01_check
echo '{ "approval_limit": 1000 }' > .orchestrator/scenarios/IN1_01_check/low-limit.json
fob-worker steps run IN1_01_check --scenario low-limit

Scenarios are only for fob-worker; fob-orc doesn't push them. Commit them with your code so everyone can use them.

What a run does#

  1. Discovers the steps under src/steps/.
  2. Loads the outputs of earlier runs from temp/*.json as step_outputs.
  3. Resolves {{<slug>.<field>}} templates in the config against them.
  4. Calls the step with a local work record (local-wr-<timestamp>) and prints the output.
  5. Saves the output to temp/<slug>.json, overwriting the last one.
Step: IN1_01_check
Config: scenario: two-invoices
Steps: src/steps/
Temp: temp

   No previous step outputs found in temp/

------------------------------------------------------------
Running step...
------------------------------------------------------------
[IN1_01_check] Raw config: {"invoices":[{"number":"INV-1001","amount":1250},{"number":"INV-1002","amount":7400}]}
[IN1_01_check] Resolved config: {"invoices":[{"number":"INV-1001","amount":1250},{"number":"INV-1002","amount":7400}]}

------------------------------------------------------------
Output:
------------------------------------------------------------
{
  "checked": 2,
  "above_limit": [
    "INV-1002"
  ]
}

   Output saved: temp/IN1_01_check.json
Step completed successfully

attachReport() and the other attach helpers write to temp/work_records/local-wr-…/ and send nothing. Anything else your step does is real: if it calls an API or writes to a system, a local run does that too. Point .env at test accounts while you develop.

Chaining steps#

Because each run saves its output and the next run loads every saved output, you can run a station's steps one after another:

fob-worker steps run IN1_01_check --scenario two-invoices
fob-worker steps run IN1_02_report --scenario from-check

IN1_02_report sees step_outputs.IN1_01_check, and a config such as { "flagged": "{{IN1_01_check.above_limit}}" } resolves to ["INV-1002"]. To start clean, delete the temp/*.json files.

When a step fails#

fob-worker prints the error and exits with status 1:

Error: [IN1_02_fail] Invalid input config:
  - threshold: Invalid input: expected number, received undefined
Error: Bank API returned 503
  • Invalid input config: the config doesn't match inputSchema. Check the Raw config and Resolved config lines; an unresolved template usually means the earlier step's output isn't in temp/.
  • Invalid output: what execute returned doesn't match outputSchema.
  • Anything else: thrown by your code. Run with DEBUG=1 for the stack trace:
DEBUG=1 fob-worker steps run IN1_01_check --scenario two-invoices

More in Troubleshooting.

Steps that process workpieces#

A step that works on bins reads and writes temp/stations/ on your machine, just as on the worker. Inspect the result with fob-worker lines status and fob-worker workpieces show. See Workpieces and bins.

Limits#

  • The built-in lib-worker:move_files step can't be run with steps run. Move folders between bins yourself.
  • Local runs have no item.
  • The output is printed for reading; the saved temp/<slug>.json is the machine-readable copy.