How a device message moves through the Redis queue system — from initial enqueue to
delivery confirmation or permanent failure. Two sections: the full state machine, then
a side-by-side deep dive of the push (LoRaWAN) and pull (Calin API) paths.
100%
Queue State Machine
Seven delivery statuses and how messages transition between them.
Push vs Pull — Detailed Paths
The divergence happens after the network server confirms receipt.
LoRaWAN relies on ChirpStack webhooks; Calin API uses a polling loop with a stored task ID.
100%
Reaper, Retry & Timeouts
Reaper Cron
Runs every 2 seconds in production. In each pass:
Expires timed-out messages in queue_in_flight_to_ns (20s)
Scans push queues for GW (15min) and device (12s) timeouts; extends GW if still on ChirpStack
Scans pull queues for max-age violations (48h) → permanent failure
Releases messages in queue_awaiting_retry whose backoff has elapsed
Triggers a new distribute-to-NS cycle
Retry Mechanics
Most failures go through retryOrFail before reaching DELIVERY_FAILED.
Max retries: 11 (12 total attempts)
Backoff: 2s base, doubles each retry, capped at 1 hour
Jitter: 0–50% random offset added to reduce thundering herd
skipRetry: bad token, device not in ChirpStack, unsupported command → immediate final failure
Timeout Reference
NS accept: 20s — both push and pull
GW delivery (push): 15 min — extendable if still on ChirpStack queue
Device response (push): 12s after tx-ack
Correlation window: 10s — ACK and uplink must arrive within 10s of each other