Idempotent commands
cmdIdMACHINE_DISPATCH_ATTEMPTSMACHINE_REPLY_TIMEOUT_MSMACHINE_DISPATCH_TTL_MSsnapshotEvery command carries an id and an expiry, so a retry is answered rather than run twice, and a late copy is refused.
The situation
Networks on a factory floor drop packets. The gateway must retry a dispatch that got no reply, and the machine must not start the same job twice when both copies arrive. A command that waited in a broker queue for an hour must not run when the machine wakes.
The recipe
The generic line protocol wraps every message in { v, id, at, source, body }. A command body carries its cmdId:
{ "v": "1", "id": "4b0e...", "at": "2026-10-23T14:02:11.000Z", "source": { "site": "site-1", "line": "line-1", "machine": "bond-01" }, "body": { "cmdId": "c-91f2", "op": "start", "args": {} } }The gateway’s patience is configuration:
MACHINE_REPLY_TIMEOUT_MS=5000MACHINE_DISPATCH_ATTEMPTS=3MACHINE_DISPATCH_TTL_MS=600000Each retry reuses the same cmdId. The machine replies accepted, and may later reply completed or failed under the same id. When no reply comes after every attempt, the gateway asks for the machine’s snapshot before deciding: a job the snapshot lists counts as accepted.
The guarantee
A repeated cmdId is answered, never run twice. A command expires at the end of the asking, so a copy that reaches the machine later is refused. A machine that restarts with a new boot id gets its accepted jobs dispatched again under the same command ids. Commands go to the broker at QoS 1, so they queue for a machine that is away. See Machines.
Related patterns
The physical world
Command a machine with a row
Start, stop, pause or change over a machine by parking a row on its role; the machine's reply resolves the row as data.
The physical world
One leader per line
Every replica runs the same config; one holds a Postgres advisory lock per line and runs its gateway, and the rest take over on loss.
The escalation boundary
One crash-safe write
The row, its facets and the resume timer commit with the workflow's checkpoint in one write. A crash leaves all of it or none of it.
