Event-Driven Inventory in Odoo: Making MQTT Subscriptions Production-Grade
Event-Driven Inventory in Odoo: Making MQTT Subscriptions Production-Grade
Odoo Integration

Event-Driven Inventory in Odoo: Making MQTT Subscriptions Production-Grade

Forty fixed readers, six handhelds and two portals all publish into one broker. The difference between a working pilot and a working plant is not the broker choice — it is the event contract, the subscriber process, duplicate handling and the ability to prove the pipeline is alive at 3 a.m.

11 min· By SpidersRFID Editorial Team

Most RFID projects begin with one reader writing into one database, and end with forty readers writing into the same database faster. The interesting part is the stretch between those two states, and it is almost never about which broker you installed.

Why MQTT fits RFID event flows

An RFID estate produces a spiky, one-way, high-volume stream of small messages, and that shape has consequences.

  • Events are tiny and frequent; a polling REST call per tag is wasteful by three orders of magnitude.
  • Readers sit on unreliable industrial networks, so the transport must tolerate reconnects without losing state.
  • The publisher knows nothing about the consumer, and should stay that way; readers must not carry ERP logic.
  • Topics give you a natural partition by site, zone and device, which is also how you scale consumers.
  • MQTT keeps a persistent session, so a subscriber that reconnects can recover messages it missed.

That last point is the one most teams rely on and most teams misconfigure.

The contract, not the broker, is the integration

Brokers are commodities. The event schema is the asset, and it needs the same discipline as a database table.

  • Version the payload from day one, in the message itself, not in the topic name.
  • Fix the identity fields: device id, site code, antenna, read time in UTC, EPC, RSSI, and a monotonic sequence.
  • Define what a "read" means: a single antenna event, or a deduplicated observation window.
  • Decide where business meaning is attached: the reader reports facts, the subscriber interprets them.
  • Write the schema down and generate both the publisher and the subscriber types from it.

If two sites can produce different field names for the same fact, you do not have an integration; you have two integrations that happen to share a broker.

Run the subscriber outside the request workers

The most common production failure is architectural, not technical: the subscriber is bolted into the same process that serves web requests.

  • Odoo web workers are short-lived and recycled; a long-lived subscription does not belong there.
  • Run a separate service with its own process supervision, its own memory budget and its own restart policy.
  • Give it a database connection separate from the pool used by users, with its own statement timeouts.
  • Never let an event handler hold a transaction open while waiting for the next message.
  • Deploy it with the same pipeline as the application, but on its own release cadence when needed.

A subscriber that dies when a user uploads a large file is not a subscriber; it is a hostage.

QoS, duplicates and the retained-message trap

Quality of service levels are often chosen by habit, which produces both lost events and duplicated inventory moves.

  • QoS 0 loses messages on reconnect; acceptable for telemetry, not for stock movements.
  • QoS 1 guarantees arrival and explicitly permits duplicates; your handler must therefore be idempotent.
  • QoS 2 removes duplicates at the protocol level but costs round trips and is rarely worth it here.
  • Retained messages are for last-known state, not for history; never retain a stock movement.
  • Clean sessions drop the queue on reconnect; if you need recovery, use a persistent session and a client id that never changes.

Choose QoS 1 plus an idempotent handler, and spend your effort on the handler.

Idempotency, ordering and clock discipline

Two events about the same pallet can arrive out of order, twice, or both.

  • Build the idempotency key from device, EPC, antenna and read timestamp, then enforce it with a unique index.
  • Do not trust device clocks; store the receive time as well as the reported time.
  • Handle out-of-order arrivals by comparing event timestamps, not arrival order.
  • For adjustments, write an append-only event log and derive the balance, rather than mutating a quantity in place.
  • Make replays safe by design, so an operator can re-run last night's batch without fear.

Inventory that can only be corrected by hand is inventory that will be corrected by hand every week.

Backpressure, batching and the dead-letter queue

A subscriber that keeps up on a quiet Tuesday will fall behind during a full physical count.

  • Batch writes in small groups with a bounded flush interval, so throughput rises without long latency.
  • Apply backpressure deliberately: slow the consumer group, never drop silently.
  • Route poison messages to a dead-letter topic with the original payload and the failure reason.
  • Alert on dead-letter growth, because a silent queue is how data loss hides.
  • Cap retries with exponential backoff, then park the message for human review.

The dead-letter queue is not an admission of failure; it is the difference between a bad afternoon and a corrupt ledger.

Security and multi-site tenancy

An open broker inside a factory network is an inventory manipulation tool for anyone who finds it.

  • Terminate TLS at the broker, and authenticate every device with per-device credentials, not one shared password.
  • Authorise topics, so a reader in warehouse A cannot publish into warehouse B's namespace.
  • Keep payloads free of personal data where possible; if a tag maps to a person, encrypt or tokenise that mapping.
  • Rotate credentials on a schedule and on device retirement, and log every rotation.
  • Separate the subscriber's read permissions from its write permissions at the database level.

Observability: proving the pipeline is alive

The question at 3 a.m. is never "is the broker up"; it is "did the last hour of reads reach Odoo".

  • Track message age end to end: publish time minus commit time, with an alert threshold.
  • Emit a heartbeat per device and alert when a device goes quiet during operating hours.
  • Count messages received, processed, deduplicated and rejected, and expose the four numbers together.
  • Keep a reconciliation job that compares event counts with resulting stock moves for the last hour.
  • Log a correlation id from reader to Odoo record, so a single disputed read can be traced in minutes.

None of this is exotic. It is the ordinary discipline of treating an event pipeline like a financial system, because that is what it becomes the moment stock depends on it.

Odoo RFID Integration — one-stop solution

We use cookies to improve your browsing experience, analyze site traffic and personalize content. Click “Accept All” to consent to all cookies, or choose “Necessary Only”. See our Privacy Policy for more details.