When an MQ Light application publishes a message, even if it uses QOS 1 (at-least-once delivery), if no subscribers have been connected before now the message will be lost. This is because the queue manager checks for any subscriptions that match the publication topic and if there are none, discards the message. This can be a problem when you are provisioning a new queue manager because you end up with a race to see if the subscribers can connect and subscribe before the publishes can publish their first few messages. Even if you can control the order that you start your subscribers and publishers, you still need to be sure the subscription has been created by the subscriber before the publisher sends any messages. If they are separate applications that are started asynchronously this can be difficult.
Unfortunately there is no way in the MQ Light API of checking that a published message has been received by anyone. However, one way to ensure you don't lose messages is to define an administered subscription on the queue manager before starting any AMQP channels. By creating an administered subscription you can make sure that any messages published by MQ Light applications will be received by the administered subscription and stored on the subscription queue until a subscriber connects. It is important that the administered subscription is created before starting any AMQP channels so that you can be sure it exists before any MQ Light publishes take place. When a subscriber finally does connect it will start to receive any messages stored up on the administered subscription queue. From then on, any messages published for the subscriber will be received by it as usual.
There are a few things to bear in mind when creating the administered subscription:
- Subscriptions used by MQ Light clients follow a specific naming scheme. If you create your administered subscription with any old name the MQ Light consumer won't use it. See the example below for the naming scheme to use.
- The topic string of the administered subscription must match exactly the topic string the MQ Light consumer is going to use.
- If you have multiple subscribers with different topic patterns you will need to create an administered subscription for each one.
- Likewise if you have multiple subscribers that use the same topic pattern but have different client IDs you will need an administered subscription for each one.
In the following example an MQ Light subscriber will connect and subscribe to the topic "payments/uk/#" as soon as an AMQP channel is available on localhost:5672. There is a also a publishing MQ Light application that will connect to the same channel as soon as it has started, and will begin publishing messages straight away. If the publisher managers to connect first the subscriber won't receive the first few messages which will be discarded by the queue manager.
To stop that happening we'll define an administered subscription once the queue manager has started, but before the AMQP channel has. Here are the steps in our script:
- crtmqm PAYMENTS.QM
- strmqm PAYMENTS.QM
- echo "DEFINE SUB(':private:subscriberClientId01:payments/uk/#') TOPICOBJ(SYSTEM.BASE.TOPIC) TOPICSTR('payments/uk/#') DESTCLAS(MANAGED)" | runmqsc PAYMENTS.QM
- echo "START SERVICE(SYSTEM.AMQP.SERVICE)" | runmqsc PAYMENTS.QM
- echo "START CHANNEL(SYSTEM.DEF.AMQP)" | runmqsc PAYMENTS.QM"
- start the publisher and subscriber
Note the naming scheme for MQ Light subscriptions:
If the subscription is going to be shared by multiple MQ Light consumers, use the following naming scheme:
- If you have used a non-default value for the TPROOT attribute of the AMQP channel you should use this as the value of TOPICOBJ when you create the subscription, rather than SYSTEM.BASE.TOPIC.
- Remember that if you don't want to lose messages if the subscriber temporarily disconnects at a later point, you must specify a long enough value for the ttl option on the MQ Light subscribe call. Otherwise the subscription will disappear when the MQ Light client next disconnects.