Lesson 3 of 7
Retries and dead letters
8 min
Listen to this lesson
Transient errors heal with time, so the cure is a retry that waits. In Cloud Integration the standard way to wait is a JMS queue: the receiving flow writes the message to a queue, and a second flow consumes it with the JMS sender adapter. If the consuming flow fails, the message stays in the queue and is retried later; once it completes, it leaves the queue. The JMS adapter uses a message broker provided by SAP and is available in all SAP Integration Suite editions except the basic edition.
The JMS sender adapter's retry settings
| Setting (Connection tab) | What it does | Limits per SAP Help |
|---|---|---|
| Retry Interval | Minutes to wait before retrying | Default 1. Exclusive queues 1–60; non-exclusive 1–10080 |
| Exponential Backoff | Doubles the interval after each failed retry | On by default in SAP's retry pattern |
| Maximum Retry Interval (in min) | Caps the doubling | Only with backoff. Default 60, minimum 10. Exclusive 10–180; non-exclusive 10–43200 |
| Dead-Letter Queue | Blocks a message that keeps crashing the worker node | Only for Non-Exclusive access; on by default |
Retry Handling settings of the JMS sender adapter.
Two facts surprise most developers. First, the channel has no "maximum retries" setting: it retries for as long as the error lasts, until the message expires from the queue. Second, the Dead-Letter Queue checkbox is not the classic dead-letter queue of other message brokers. It does not catch messages whose retries ran out. It protects the tenant from a message (usually a very large one) whose processing stopped with an out-of-memory error in the worker node: after that message has been retried twice more and crashed the node again each time, it is taken out of processing and marked Blocked, and a lock entry appears in the Monitor under Managing Locks > Message Locks. Releasing the lock starts the retries again.
Ending retries yourself: SAPJMSRetries
To stop after a number of attempts, use the header SAPJMSRetries. The JMS sender adapter sets it to the number of retries of the message, but only for Non-Exclusive queues. SAP Help suggests handling it in an exception subprocess that calls a local process for retry handling. Contoso's version in CMC_GLFS_Order_Deliver:
- The exception subprocess classifies the error (lesson 1). A functional error is parked at once; there is nothing to wait for.
- For a transient error, a Router checks
${header.SAPJMSRetries}. Below 8, the subprocess ends with Error End: the message stays Failed and JMS retries it. With backoff from 1 minute capped at 60, eight retries cover roughly three hours of CMP downtime. - At 8 or more, the subprocess writes the message to the parking queue
CMC_GLFS_ORDERS_PARKED, sets the custom statusParked, forwards the error to SAP Application Interface Framework (lesson 6) and ends with End Message. The original queue entry is consumed, so retries stop.
- Is the error functional (our own Error End)?Yes → park now and notify the business · No → next question
- Is it transient (timeout, 5xx from CMP)?Yes → next question · No → park and alert the integration team
- Is SAPJMSRetries below 8?Yes → Error End: JMS retries with backoff · No → park, custom status Parked, End Message
Choose the queue access type deliberately. Exclusive access processes messages one at a time in order, but a message in error blocks every message behind it, and SAPJMSRetries is not set. Non-Exclusive access processes in parallel without order. Great Lakes orders are independent, so Contoso uses non-exclusive. The access type must match in the JMS receiver and sender adapters and cannot be changed after the queue exists without undeploying, deleting and recreating it.
Parking and reprocessing
A parked message is a message waiting for a decision, so it must be easy to find and safe to replay. In the Monitor, the Message Queues tile under Manage Stores lists each queue's entries with status (Waiting, Overdue, Failed, Blocked), retry count, next retry and the Application Message ID. You can Move up to 100 selected messages to another queue, Retry a message on a non-exclusive queue, or Delete it (which needs PI_Administrator in the Cloud Foundry environment). To replay a parked order after Maria fixes the mapping, Theo moves it from CMC_GLFS_ORDERS_PARKED back to CMC_GLFS_ORDERS, and the delivery flow processes it as new.
A data store is the alternative parking place: a Data Store Write in the exception subprocess, with the order number as Entry ID. Entries are deleted after the Expiration Period (default 30 days, maximum 180), and Retention Threshold for Alerting marks unread entries Overdue in the Data Stores monitor. Data stores suit "keep it for inspection"; queues suit "replay it", because a move puts the message straight back into processing.
Don't confuse JMS retries with the HTTP receiver's built-in Retry on Exception and Retry on Error Response options. Those retry inside the same call, at most three times, at most 60 seconds apart, and the exception subprocess runs only after the last attempt. They smooth over a blip; they do not survive an hour-long outage.
- JMS sender retry settings: Retry Interval, Exponential Backoff, Maximum Retry Interval, Dead-Letter Queue.
- There is no maximum-retries field; stop retries yourself with SAPJMSRetries on non-exclusive queues.
- The Dead-Letter Queue option blocks messages that crash the worker node; it is not a retry-exhausted queue.
- Park on purpose: a parking queue (replay with Move) or a data store (inspect, expires by default after 30 days).
- In-call HTTP retries (max three, max 60 s apart) complement JMS retries but do not replace them.
Check your understanding · not graded
Lesson check
1. What does the Dead-Letter Queue option of the JMS sender adapter actually do?
2. You need to stop retrying a JMS message after eight attempts. What do you use?
3. Why can an exclusive JMS queue be a poor choice for independent customer orders?
4. How does Theo replay a parked order after the mapping is fixed?