Idempotency

Idempotency is how you live peacefully with IBM MQ at-least-once delivery: the same message—or two messages with the same business meaning—can arrive more than once, but your ledger, inventory, and customer accounts reflect the truth once. Banks call it duplicate detection; architects call it exactly-once processing built on at-least-once transport. Without idempotency, a crash between database commit and MQCMIT creates double charges; without business-key checks, a producer retry creates twin shipments. This page explains idempotent versus non-idempotent operations, MsgId and natural-key deduplication, status-column patterns, transactional outbox on the producer side, HTTP-style idempotency keys in payloads, poison message interaction, and testing strategies beginners can run in a lab before production traffic arrives.

Why MQ Forces You to Think About Idempotency

Syncpoint consumers MQBACK on failure; the message returns. A network blip after your database updated but before MQCMIT produces the same scenario. Channels restart and redeliver. Batch reprocessing replays files. MQ is doing reliable messaging; your code must assume duplicates are normal, not exceptional. Idempotency is not optional for money movement—it is part of the contract.

Idempotent vs non-idempotent examples
OperationIdempotent?Why
SET status=SHIPPED for order 42Yes (same end state)Repeating leaves status SHIPPED
ADD 10 to balanceNoTwice adds 20 unless guarded
INSERT payment IF NOT EXISTS keyYesSecond insert fails unique constraint
Append-only log line per MsgIdYes if keyedSame MsgId does not append twice

Deduplication Table Pattern

Create PROCESSED_MESSAGES with columns MSG_ID_BINARY, BUSINESS_KEY, PROCESSED_AT, STATUS. On get, insert within the same database transaction as business logic, or insert first with unique constraint on MSG_ID or BUSINESS_KEY. Duplicate key violation means another worker already handled it—commit MQ without repeating side effects. Choose transaction boundaries so insert and business update commit together with MQCMIT when using XA.

Status Column Pattern

ORDERS table: status NEW, PROCESSING, DONE. Transition NEW to PROCESSING with optimistic lock (UPDATE WHERE status=NEW). Only one consumer wins. Second consumer sees DONE or PROCESSING and skips. Clearer for auditors than silent no-op. Document allowed transitions to prevent illegal states.

Producer Idempotency

Before MQPUT, check whether event already published. Transactional outbox: write OUTBOX row and business row in one DB transaction; relay process puts to MQ once and marks SENT. Prevents duplicate puts from application retries. Client-supplied idempotency keys in API headers should map to dedup store at the edge before messages enter MQ.

MsgId vs Business Key

  • MsgId: same MQ message instance redelivered after MQBACK.
  • Business key: duplicate event from upstream with new MsgId.
  • Use both layers for payment-grade flows.
  • Log which key triggered skip for support.

Poison Messages and Idempotency

Idempotency does not fix poison—a message that always throws before commit will never reach DONE. BOTHRESH moves it to backout. Do not mark poison as processed in dedup table unless you intentionally skip bad data with approval. Separate quarantine workflow from duplicate skip workflow.

Tutorial: Conceptual Consumer

sql
1
2
3
4
5
6
7
8
9
-- Within same UoW as business update (conceptual): INSERT INTO processed_messages (msg_id, order_id, status) VALUES (:MsgId, :OrderId, 'DONE'); -- unique(msg_id) OR unique(order_id) -- On duplicate key: -- MQCMIT without changing balances again -- On success path: -- apply business rules, MQCMIT

Explain Like I'm Five: Idempotency

The teacher asks you to write your name on the attendance sheet. If you accidentally go to the desk twice, you check—your name is already there, so you do not write it again. The sheet looks the same as if you went once. That is idempotent.

Practice Exercises

Exercise 1: Design

Wire transfer message may redeliver. Sketch tables and commit order with MQGET syncpoint.

Exercise 2: Non-Idempotent Fix

Change ADD 10 to balance into an idempotent pattern using event id.

Exercise 3: Test

How do you test idempotency in CI—duplicate put, duplicate get, or both?

Frequently Asked Questions

Frequently Asked Questions

Test Your Knowledge

Test Your Knowledge

1. Idempotent processing means:

  • Duplicates have no extra business effect
  • Messages are never redelivered
  • MQ removes MsgId
  • Only non-persistent allowed

2. Unique index on order_id in processed_orders helps:

  • Start channels
  • Reject duplicate business processing
  • Set DEFPSIST
  • Disable syncpoint

3. MQ redelivery of the same message usually keeps:

  • Same MsgId
  • New queue manager name
  • Blank CorrelId always
  • No persistence

4. Increment account balance by 10 twice is NOT idempotent unless:

  • You use absolute balance or check last applied event id
  • You use non-persistent
  • You disable BOQNAME
  • You use topics only
Published
Read time15 min
AuthorMainframeMaster
Verified: IBM MQ 9.3 documentation