IBM MQ Guaranteed Delivery

Guaranteed delivery is the promise enterprises make to customers and regulators: payments, orders, and claims will not silently disappear when a server restarts or a network blips. IBM MQ fulfills that promise through persistent messages, logging, syncpoint commit and backout, and operational patterns for poison messages—not through a single switch labeled "guaranteed." This page explains persistent versus non-persistent messages, how DEFPSIST and MQPMO control durability, what at-least-once delivery means for application developers using MQI, and how queue managers on z/OS and distributed platforms store messages until MQGET succeeds. You will work through MQSC examples you can run on a lab queue manager and see how guaranteed delivery connects to decoupling: producers trust the queue manager to hold work until consumers are ready.

What Guaranteed Delivery Means in Practice

In middleware terms, delivery guarantees describe what happens to a message across failures. IBM MQ does not magically deliver to an application that never runs; it guarantees that the infrastructure will retain a committed persistent message until a valid consumer removes it (subject to expiry, discard policies, and administrative actions). The boundary of responsibility splits clearly: the queue manager owns storage and logging; the application owns processing logic, duplicate detection, and poison handling.

Beginners often confuse guaranteed delivery with exactly-once processing. MQ under syncpoint and with persistent messages provides strong infrastructure durability, but if a consumer gets a message, crashes before commit, and the message becomes available again, processing may run twice. Architects call that at-least-once semantics. Exactly-once business outcomes require idempotent updates—natural keys, duplicate tables, or compare-and-set in the database—layered on top of MQ.

Persistent vs Non-Persistent Messages

Every put specifies persistence (explicitly in the message descriptor MQMD Persistence field, or implicitly via queue default DEFPSIST). Persistent messages (MQPER_PERSISTENT) are written through the queue manager log to durable media before MQPUT returns success outside syncpoint, or before syncpoint commit when inside a unit of work. Non-persistent messages (MQPER_NOT_PERSISTENT) stay in volatile storage; they are appropriate for high-frequency telemetry, transient status, or scratch traffic where recreation is cheaper than disk I/O.

Mixing both types on one queue is allowed but demands clear standards. Operations monitoring must know which business events are durable. A common anti-pattern is copying production queue names into a lab with DEFPSIST(NO) while applications still assume banking-grade durability. Performance tests that disable persistence skew capacity plans and mislead stakeholders about restart behavior.

On z/OS, persistent messages interact with log streams and possibly Coupling Facility queue structures for sharing across queue managers in a sysplex. On Linux, file systems hosting log and queue directories must meet IBM recommendations for fsync behavior and RAID levels. Guaranteed delivery fails operationally when disks fill, logs cannot extend, or queue MAXDEPTH is reached—MQ will not lose committed persistent messages silently, but puts may fail with reason codes until capacity is restored.

DEFPSIST and Queue Defaults

DEFPSIST is defined on local queue objects. DEFPSIST(YES) tells the queue manager to treat incoming messages as persistent when the application leaves persistence as MQPER_AS_Q_DEF. DEFPSIST(NO) defaults to non-persistent. Administrators align DEFPSIST with the queue purpose: PAYMENT.REQUEST with YES, METRICS.STREAM with NO. Applications can override per put using the MQMD or MQPMO persistence options—essential when a single queue carries mixed traffic, though separate queues are cleaner for operations.

Related attributes include DEFPRTY (default priority) and DEFPRESP (default put response). While not strictly delivery guarantees, they affect ordering and whether the putter waits for confirmation. DEFPRESP with synchronous responses can strengthen the application's knowledge that persistence completed before continuing—useful in some payment designs.

MQPMO and Application Put Options

The Put Message Options (MQPMO) structure controls put behavior. MQPMO_SYNCPOINT includes the put in the current unit of work; the message is not visible to other applications until MQCMIT. MQPMO_NO_SYNCPOINT puts outside the UOW—still persistent if the descriptor says so, committed when the put completes. MQPMO_NEW_MSG_ID and correlation options support request/reply tracking across retries.

Language bindings map these options: Java JMS delivery mode persistent versus non-persistent; .NET and C MQI structures mirror MQPMO and MQMD fields. A CICS program might issue EXEC CICS SYNCPOINT after successful MQPUT under the same UOW as file updates. Understanding the pairing of MQMD persistence, MQPMO syncpoint, and MQCMIT is central to guaranteed delivery in transactional systems.

Example conceptual flow: open queue, set MQMD Persistence to MQPER_PERSISTENT, set MQPMO with SYNCPOINT, MQPUT, update Db2, MQCMIT. If Db2 fails, MQBACK rolls back the put and the message never appears on the queue. If MQPUT fails, the application should not commit the database. That coordination is how mainframe estates keep ledger and messaging aligned.

Syncpoint, Commit, and Backout

Syncpoint defines atomic units across one or more MQ operations and optionally other resource managers. MQCONN or MQCONNX establishes whether the connection is syncpoint capable. Within a unit of work, multiple puts and gets are provisional until commit. MQCMIT makes them permanent; MQBACK undoes them.

On the consumer side, get-commit processing is equally important. A common pattern: MQGET under syncpoint, process, update database, MQCMIT. If processing fails, MQBACK returns the message to the queue (incrementing backout count). That is how at-least-once interacts with failure: the message was never committed as consumed, so another consumer can receive it again.

Global units of work and two-phase commit appear when MQ coordinates with Db2 on z/OS or other XA resource managers. The beginner takeaway: guaranteed delivery to disk is not the same as guaranteed exactly-once business processing—syncpoint spans both messaging and application data when configured.

At-Least-Once, At-Most-Once, and Exactly-Once

At-least-once means a message may be delivered one or more times until processing commits successfully. IBM MQ with persistent messages and get under syncpoint typically provides at-least-once when applications back out on failure. At-most-once can occur with non-persistent messages or when consumers commit gets before finishing work—risky for money. Exactly-once end-to-end is a business property: MQ plus idempotent consumer plus deduplication store.

Delivery semantics overview
SemanticMQ roleApplication role
At-least-oncePersistent storage; get under syncpoint; backout on failureTolerate duplicates; use idempotent updates
At-most-onceNon-persistent or commit get before processAccept possible loss on failure
Exactly-once (business)Durable messaging plus transactional coordinationDedup keys; unique constraints; outbox patterns

Poison Messages and Dead-Letter Queues

A poison message causes repeated processing failure—every get ends in backout. Without intervention, it reaches BOTHRESH (backout threshold) and moves to BOQNAME (backout queue) if defined, or blocks the queue when consumers cannot skip it. Operations move poison messages to a dead-letter queue (DLQ) for analysis, fix the payload or code, and optionally requeue.

Poison messages do not mean MQ broke guaranteed delivery; they mean the application cannot process valid data. DLQ depth alerts are as important as business queue depth. Request/reply flows can poison reply queues if correlation IDs are wrong. Report messages can help trace where delivery failed in multi-hop channel routes.

Designing poison handling early: set BOTHRESH and BOQNAME on critical queues, document requeue procedures, and log message IDs. Mainframe and distributed teams share responsibility—COBOL and Java consumers must use consistent backout logic.

Channels and Guaranteed Delivery Across Systems

When messages route between queue managers, persistent messages are transmitted so the receiving queue manager logs them before acknowledging. Channel failures trigger retry; messages remain on the transmission queue until the channel succeeds or operations intervene. Guaranteed delivery across sites assumes channels are correctly paired, TLS and auth are sound, and disk capacity exists on both sides.

Decoupling across data centers depends on this behavior: a payment put in London persists locally, crosses the channel to z/OS, and persists again before the hub acknowledges. Monitoring channel status (RUNNING, RETRYING) is part of delivery assurance, not optional networking detail.

Tutorial: MQSC for Persistence and Backout

Create a durable payments queue with persistence default and backout handling, then display attributes. Replace QM1 with your lab queue manager name.

shell
1
2
3
4
5
6
7
8
9
10
# Define persistent payment queue with backout handling echo "DEFINE QLOCAL('PAYMENT.REQUEST') REPLACE + DESCR('Persistent payment requests') + DEFPSIST(YES) MAXDEPTH(100000) MAXMSGL(4194304) + BOTHRESH(3) BOQNAME('PAYMENT.REQUEST.BOQ') DEFINE QLOCAL('PAYMENT.REQUEST.BOQ') REPLACE + DESCR('Backout queue for poison messages') + DEFPSIST(YES) MAXDEPTH(10000) ALTER QMGR DEADQ('SYSTEM.DEAD.LETTER.QUEUE') DISPLAY QLOCAL('PAYMENT.REQUEST') DEFPSIST BOTHRESH BOQNAME CURDEPTH" | runmqsc QM1

DEFPSIST(YES) ensures default persistent messages. BOTHRESH(3) moves a message to PAYMENT.REQUEST.BOQ after three backouts. Verify DEADQ is set on the queue manager so unroutable messages have a destination. Application puts should still set MQPMO_SYNCPOINT for transactional payments and MQMD persistence when overriding defaults.

Tutorial: Shell Check of Log and Queue Paths (Distributed)

On Linux lab systems, persistent messages depend on log and queue directories. Inspect paths configured on the queue manager (values vary by installation).

shell
1
2
3
4
# Display queue manager log and queue paths (Linux example) echo "DISPLAY QMGR LOGPATH QMNAME STATUS" | runmqsc QM1 # Example follow-up: verify disk space on those filesystems df -h $(echo "DISPLAY QMGR LOGPATH" | runmqsc QM1 | grep LOGPATH | awk '{print $2}')

Full disk on the log volume prevents commits and breaks guaranteed delivery from an operations perspective. Include filesystem monitoring in runbooks alongside DISPLAY QLOCAL CURDEPTH.

Explain Like I'm Five: Guaranteed Delivery

You put a drawing in a metal locker (persistent message) instead of on a sticky note on a windy playground table (non-persistent). The school (queue manager) promises the drawing stays in the locker until your friend opens it with the right key (MQGET commit). If your friend tries to copy the drawing but drops their pencil and gives up (application failure before commit), the drawing goes back in the locker for another try (at-least-once). If the drawing is impossible to read—scribbles with no picture—a teacher moves it to a special problem locker (backout or dead-letter queue) so other kids' drawings can still be collected.

Practice Exercises

Exercise 1: Persistence Decisions

Classify each as persistent or non-persistent and justify: wire transfer instruction, heartbeat ping every second, settlement file pointer, session cookie for a shopping cart. Note which would use DEFPSIST on the queue definition.

Exercise 2: Syncpoint Narrative

Write step-by-step what happens when a consumer MQGETs under syncpoint, crashes after processing but before MQCMIT, and restarts. Why might the business see duplicate posting if the consumer is not idempotent?

Exercise 3: Poison Message Design

For queue CLAIMS.INTAKE, propose BOTHRESH, BOQNAME, and DLQ handling in five sentences. Who requeues messages after a fix—the application team or operations?

Exercise 4: MQSC Hands-On

Define a lab queue EXERCISE.PERSIST with DEFPSIST(YES) and BOTHRESH(2). Put two test messages with amqsput if available. DISPLAY CURDEPTH and DEFPSIST. Alter DEFPSIST to NO, put again, and describe restart risk in two sentences.

Test Your Knowledge

Test Your Knowledge

1. When is a persistent message considered safely on the queue?

  • When the sender prints a log line
  • When the queue manager has logged it to durable storage and the put (and syncpoint if used) commits
  • When the receiver channel starts
  • When DEFPSIST is NO

2. What does at-least-once delivery imply for application design?

  • Messages are never duplicated
  • Consumers may see the same logical message more than once and must handle duplicates safely
  • Persistence is disabled
  • Channels are not required

3. Which queue attribute sets default message persistence?

  • MAXDEPTH
  • DEFPSIST
  • GET
  • TRIGGER

4. What is the purpose of BOTHRESH and BOQNAME?

  • Encrypt messages on the queue
  • Move messages that exceed backout count to a backout queue for poison message handling
  • Start the listener automatically
  • Define TLS cipher suites
Published
Read time14 min
AuthorMainframeMaster
Reviewed by MainframeMaster teamVerified: IBM MQ 9.3 documentationSources: IBM MQ product documentation, IBM MQ application programming referenceApplies to: IBM MQ 9.3, z/OS and distributed