JMS 2.0 delivery delay
With JMS 2.0, we can specify a delivery delay when sending a message. The queue manager does not deliver the message until after the specified delivery delay has elapsed.
An application can specify a delivery delay in milliseconds, when it sends a message, by using either MessageProducer.setDeliveryDelay(long deliveryDelay) or JMSProducer.setDeliveryDelay(long deliveryDelay). This value is added to the time at which the message is sent and gives the earliest time at which any other application can get that message.
In IBM MQ Version 8.0 and later, delivery delay is implemented by using a single internal staging queue. Messages that have a nonzero delivery delay are placed on this queue with a header that indicates the delivery delay and information about the target queue. A component of the queue manager that is called the delivery delay processor monitors the messages on the staging queue. When a message's delivery delay completes, the message is taken off the staging queue and placed on the target queue.
Messaging clients
The IBM MQ implementation of delivery delay is only available for use when we are using the JMS client. The following restrictions apply if we are using delivery delay with IBM MQ. These restrictions apply equally to MessageProducers and JMSProducers, but JMSRuntimeExceptions are thrown in the case of JMSProducers.
- Any attempt to call MessageProducer.setDeliveryDelay with a nonzero value when connected to an IBM MQ queue manager earlier than Version 8.0, results in a JMSException with a MQRC_FUNCTION_NOT_SUPPORTED message.
- Delivery delay is not supported for clustered destinations that have a DEFBIND value other than MQBND_BIND_NOT_FIXED. If a MessageProducer has a nonzero delivery delay set and an attempt is made to send to a destination that does not meet this requirement, then the call results in a JMSException with an MQRC_OPTIONS_ERROR message.
- Any attempt to set a time to live value that is less than a previously specified nonzero delivery delay, or vice versa, results in a JMSException with a MQRC_EXPIRY_ERROR message. This checking is done on calling setTimeToLive or setDeliveryDelay or send methods, depending on the exact set of operations chosen.
- Use of retained publications and delivery delay is not supported. Attempting to publish a message with a delivery delay if that message has been marked as retained by using msg.setIntProperty(JmsConstants.JMS_IBM_RETAIN, JmsConstants.RETAIN_PUBLICATION) results in a JMSException with a MQRC_OPTIONS_ERROR message.
- Delivery delay and message grouping is not supported and any attempt to use this combination results in a JMSException with a MQRC_OPTIONS_ERROR message.
Any failure to send a message with delivery delay results in the client throwing a JMSException with a suitable error message, for example queue full. In some situations, the error message might apply to the target destination, or the staging queue, or both.
Note: IBM MQ allows applications that put a message in a unit of work to get the same message again even though the unit of work has not committed. This technique does not work with delivery delay as the message is not placed on the staging queue until the unit of work is committed, and as a result will not have been sent to the target destination.Authorization
IBM MQ carries out authorization checks on the original target destination when the application sends a message with a nonzero delivery delay. If the application is not authorized, then the send fails. When the queue manager detects that a message's delivery delay is complete, it opens the target queue. No authorization checks are carried out at this point.
SYSTEM.DDELAY.LOCAL.QUEUE
A new system queue, SYSTEM.DDELAY.LOCAL.QUEUE, is used to implement delivery delay.- On Multiplatforms, SYSTEM.DDELAY.LOCAL.QUEUE exists by default. The system queue must be altered so that its MAXMSGL and MAXDEPTH attributes are sufficient for the expected load.
- On IBM MQ for z/OS, SYSTEM.DDELAY.LOCAL.QUEUE is used as a staging queue for messages that are sent with delivery delay to both local and shared queues. On z/OS, the queue must be created and must either be defined so that its MAXMSGL and MAXDEPTH attributes are sufficient for the expected load.
When this queue is created, it must be secured so that as few users as possible have access to it. Access to the queue must be for maintenance and monitoring purposes only.
When a message is sent by a JMS application with a nonzero delivery delay, it is put to this queue with a new message ID. The original message ID is placed in the correlation ID of the message. This correlation ID allows an application to retrieve a message from the staging queue when required, for example if a large delivery delay was used by mistake.
Considerations for z/OS
If the system is running on z/OS, there are additional considerations to take into account if we want to use delivery delay.
If delivery delay is to be used, the system queue SYSTEM.DDELAY.LOCAL.QUEUE must be defined. It must be defined with a storage class that is sufficient for its expected load, and with HARDENBO, STGCLASS('DEFAULT'), INDXTYPE(NONE), and MSGDLVSQ(FIFO) specified. A sample definition of the system queue is provided, commented out, in the CSQ4INSG JCL.
Shared queues
Delivery delay is supported for sending messages to shared queues. However, there is only a single, private staging queue that is used regardless of whether the target queue is shared or not. The queue manager that owns that private queue must be running to send the delayed message to its target shared queue when the delay completes. Note: If a non-persistent message is put with a delivery delay to a shared queue, and the queue manager that owns the staging queue shuts down, the original message is lost. As a result non-persistent messages sent with delivery delay to a shared queue are more likely to be lost than non-persistent messages sent without delivery delay to a shared queue.Target destination resolution
If the message is sent to a queue, resolution is driven twice; once by the JMS application and once by the queue manager when it takes the message off the staging queue and sends it to the target queue.
Target subscriptions for publications are matched when the JMS application calls the send method.
If a message is sent with persistence or priority according to the queue definition, then the value is set on the first resolution and not the second.Expiry interval
Delivery delay preserves the behavior of the expiry property, MQMD.Expiry. For example, if a message was put from a JMS application with an expiry interval of 20,000 ms and a delivery delay of 5,000 ms, and got after an elapsed time of 10,000 ms, then the value of the MQMD.expiry field might be approximately 50 tenths of a second. This value indicates that 15 seconds has elapsed from the time the message was put, to the time when it was got.
If a message expires while on the staging queue and one of the MQRO_EXPIRATION_* options is set, then the report generated is for the original message as sent by the application, the header used to contain the delivery delay information is removed.
Stopping and starting the delivery delay processor
On z/OS, the delivery delay processor is integrated into the queue manager MSTR address space. When the queue manager starts, the delivery delay processor also starts. If the staging queue is available, it opens the queue and waits for messages to arrive on it to be processed. If the staging queue has not been defined, or is disabled for gets, or another error occurs, the delivery delay processor shuts down. If the staging queue is later defined, or altered to be get enabled, the delivery delay processor restarts. If the delivery delay processor shuts down for any other reason, it can be restarted by altering the PUT attribute of the staging queue from ENABLED to DISABLED and back to ENABLED again. Should we need to stop the delivery delay processor for any reason, set the PUT attribute of the staging queue to DISABLED.
On Multiplatforms, the delay processor starts with the queue manager, and is automatically restarted in the event of a recoverable failure.
Failure to put to target queue
If a delayed message cannot be put to the target queue once its delay completes, the message is dealt with as indicated in its report options: it is either discarded or sent to the dead letter queue. If this action fails, then an attempt is made to put the message later. If the action is successful an exception report is generated and sent to the specified queue, if the report is requested. If the report message could not be sent, the report message is sent to the dead letter queue. If sending the report to the dead letter queue fails and the message is persistent, all changes are discarded and the original message rolled back and redelivered later. If the message is non-persistent the report message is discarded, but other changes are committed. If a delayed publication cannot be delivered because a subscriber has unsubscribed, or in the case of a non-durable subscriber, because it has disconnected, then the message is discarded silently. Report messages are still generated as described earlier.
If a delayed publication cannot be delivered to a subscriber and is instead put to the dead letter queue, and the put to the dead letter queue fails then the message is discarded.
To reduce the likelihood of the put to the target queue failing after the delivery delay has completed, the queue manager performs some basic checks when the JMS client sends a message with a nonzero delivery delay. These checks include whether the queue is put disabled, if the message is bigger than the maximum message length allowed, and if the queue is full.
Publish/subscribe
Matching of a publication to available subscriptions occurs when the JMS application sends a message with a nonzero delivery delay. A message for each matching subscriber is put to the SYSTEM.DDELAY.LOCAL.QUEUE queue, where it is kept until the delivery delay completes. If one of those subscribers is a proxy subscription for another queue manager, then the fan-out on that queue manager occurs after the delivery delay is complete. This might result in subscribers on the other queue manager receiving publications that were originally published before they subscribed. This is a deviation from the JMS 2.0 specification.
Delivery delay with publish/subscribe is only supported if the target topic is configured with (N)PMSGDLV = ALLAVAIL. An attempt to use any other values results in a MQRC_PUBLICATION_FAILURE error. If the delivery delay processor fails while it is putting the message to the target queue, the result is as described in the "Failure to put to target queue" section.
Report messages
All report options are supported and actioned by the delivery processor, other than the following options that are ignored, but passed through on the message when it is sent to the target queue:
- MQRO_COA*
- MQRO_COD*
- MQRO_PAN/MQRO_NAN
- MQRO_ACTIVITY
Parent topic: Use JMS 2.0 functionality