--- type: concept tags: [parking, printer, device, reliability] sources: [] updated: 2026-06-14 --- # Printer roles & failover A lane runs **more than one printer**, and the system knows each one's job so it can fail over automatically. This is a reliability decision, not a threat-model one: an entry ticket must still print when the outside dispenser jams or drops off the network. ## Roles Each printer instance (a `lane_devices` row, category `printer`) declares a **role** in its config: - **`entry-dispenser`** — outside, at the lane. Prints the entry ticket the driver takes. - **`booth-receipt`** — inside the booth. Prints receipts at exit/payment, AND serves as the **backup** for entry tickets. It also declares a **`failoverRank`** (higher = preferred within a role) to order multiple printers of the same role deterministically (ties broken by id). ## Failover rule (asymmetric, on purpose) For an **entry ticket** (`wantRole = entry-dispenser`): try the entry dispensers (best rank first), then fall back to the **booth printer**. So a driver still gets a ticket when the outside unit is offline — the operator hands it over from the booth. The reverse is **deliberately not** done: a **receipt** never prints on the outside dispenser. Receipts are a booth-only job; an entry dispenser falling back to print receipts makes no physical sense. ## Where the logic lives - The driver (`rongta`) is **role-agnostic** — role/rank are just config; the transport doesn't care. Keeps [[device-adapter-pattern|adapters]] swappable. - Selection is pure logic in `packages/devices/printer-routing.ts`: `orderForRole()` ranks candidates; `printWithFailover()` attempts the print down the list and throws `NoPrinterAvailableError` only when every candidate fails. - It **attempts the print directly** rather than racing a `healthCheck` first — the print is the real reachability test, and a health probe that passes can still be followed by a failed print. ## Open: the all-printers-down policy When `printWithFailover` exhausts every candidate, what should entry do — raise the barrier with no paper ticket (the plate/[[lpr-camera]] is the independent record), or hold? That policy belongs to the **entry flow** ([[device-input-flow]], [[fail-state-safety]]), not the printer layer, and is **not yet decided**. The signed event ([[append-only-event-chain]]) is created regardless of whether paper prints.