A field device is offline for hours at a time, and operators change its settings while it is away - sometimes twice. What should the platform store?
Show the full answer Hide the answer
The deciding property
Settings are state, and state changes are not events to be replayed. If an operator sets a temperature to 18, then to 22, the device should end at 22 and should never pass through 18. A queue guarantees that it does pass through 18, because a queue is a record of intentions rather than of intent.
A desired-state document is idempotent and convergent: the device fetches it on reconnect, diffs it against what it is running, and applies the difference once. Two changes while offline collapse into one application, and a device that misses three updates converges in a single step.
The reported half is not decoration. The gap between desired and reported is the fleet's health metric — alert on the count of devices diverged for longer than the expected check-in interval, and you have a single signal that covers failed applications, lost connectivity and devices that acknowledge but do not comply.
Why the other options fail
- The command queue. Ordering is its selling point and its defect. It also grows without bound while a device is away — three weeks at a few commands an hour is over 1000 entries to deliver in one burst — and it executes stale intentions on reconnect, which for anything physical ranges from confusing to dangerous: "turn on the heater" issued nineteen days ago. The queue costs you an unbounded buffer and an expiry policy to gain an ordering guarantee that settings do not need.
- Direct RPC that fails fast. Correct for a live interactive session with a connected device, and it simply does not answer the question, which is what happens when the device is not there.
- An event log the device replays from an offset. It re-executes history, which is exactly what a settings change must not do, and the offset is state the device may lose — after which it replays everything or nothing.
The part the answer does not cover
Genuinely imperative actions are not state: reboot, unlock, capture an image, run a diagnostic. Those need a command with an explicit time-to-live, an idempotency key and an acknowledgement, so that a command which could not be delivered in time expires instead of executing late. A mature platform has both mechanisms and is clear about which one each operation uses. The test is simple: if issuing it twice should have the same effect as once, it is state; if not, it is a command with an expiry.
When not to build a twin at all
For devices on a reliable network that are always connected, a settings API and a status endpoint are the whole design. A shadow exists to absorb absence; where absence is rare and brief, it adds a second source of truth and a reconciliation loop to debug, which is a real cost every time something goes wrong in production. Build it when devices are routinely away for longer than an operator is willing to wait.