Example 2: Managed MQ subscriber
The managed MQ subscriber is the preferred pattern for most subscriber applications. The example requires no administrative definition of queues, topics or subscriptions.
This simplest kind of managed subscriber typically uses a non-durable subscription. The example focuses on a non-durable subscription. The subscription lasts only as long as the lifetime of the subscription handle from MQSUB. Any publications that match the topic string during the lifetime of the subscription are sent to the subscription queue (and possibly a retained publication if the flag MQSO_NEW_PUBLICATIONS_ONLY is not set or defaulted, an earlier publication matching the topic string was retained, and the publication was persistent or the queue manager has not terminated, since the publication was created).
We can also use a durable subscription with this pattern. Typically if a managed durable subscription is used it is done for reliability reasons, rather than to establish a subscription that, without any errors occurring, would outlive the subscriber. For more information about different life cycles associated with managed, unmanaged, durable and non-durable subscriptions see the related topics section.
Durable subscriptions are often associated with persistent publications, and non-durable subscriptions with non-persistent publications, but there is no necessary relationship between subscription durability and publication persistence. All four combinations of persistence and durability are possible.
For the managed non-durable case considered, the queue manager creates a subscription queue that is purged and deleted when the queue is closed. The publications are removed from the queue when the non-durable subscription is closed.
The valuable facets of the managed non-durable pattern exemplified by this code are as follows:
- On demand subscription: the subscription topic string is dynamic. It is provided by the application when it runs.
- Self managing queue: the subscription queue is self defining and managing.
- Self managing subscription lifecycle: non-durable subscriptions only exist for the duration of the subscriber application.
- If you define a durable managed subscription, then it results in a permanent subscription queue and publications continue to be stored on it with no subscriber programs being active. The queue manager deletes the queue (and clears any unretrieved publications from it) only after the application or administrator has chosen to delete the subscription. The subscription can be deleted using an administrative command, or by closing the subscription with the MQCO_REMOVE_SUB option.
- Consider setting SubExpiry for durable subscriptions so that publications cease to be sent to the queue and the subscriber can consume any remaining publications before removing the subscription and causing the queue manager to delete the queue and any remaining publications on it.
- Flexible topic string deployment: Subscription topic management is simplified by defining the root part of the subscription using an administratively defined topic. The root part of the topic tree is then hidden from the application. By hiding the root part an application can be deployed without the application inadvertently creating a topic tree that overlaps with another topic tree created by another instance, or another application.
- Administered topics: by using a topic string in which the first part matches an administratively defined topic object, publications are managed according to the attributes of the topic object.
- For example, if the first part of the topic string matches the topic string associated with a clustered topic object, then the subscription can receive publications from other members of the cluster
- The selective matching of administratively defined topic objects and programmatically defined subscriptions enables you to combine the benefits of both. The administrator provides attributes for topics, and the programmer dynamically defines subtopics without being concerned about the management of topics.
- It is the resultant topic string which is used to match the topic object that provides the attributes associated with the topic, and not necessarily the topic object named in sd.Objectname, although they typically turn out to be one and the same. See Example 2: Publisher to a variable topic.
By making the subscription durable in the example, publications continue to be sent to the subscription queue after the subscriber has closed the subscription with the MQCO_KEEP_SUB option . The queue continues to receive publications when the subscriber is not active. We can override this behavior by creating the subscription with the MQSO_PUBLICATIONS_ON_REQUEST option and using MQSUBRQ to request the retained publication.
The subscription can be resumed later by opening the subscription with the MQCO_RESUME option.
We can use the queue handle, Hobj, returned by MQSUB in a number of ways. The queue handle is used in the example to inquire on the name of the subscription queue. Managed queues are opened using the default model queues SYSTEM.NDURABLE.MODEL.QUEUE or SYSTEM.DURABLE.MODEL.QUEUE. We can override the defaults by providing your own durable and non-durable model queues on a topic by topic basis as properties of the topic object associated with the subscription.
Regardless of the attributes inherited from the model queues, we cannot reuse a managed queue handle to create an additional subscription. Nor can you obtain another handle for the managed queue by opening the managed queue a second time using the returned queue name. The queue behaves as if it has been opened for exclusive input .
Unmanaged queues are more flexible than managed queues. We can, for example share unmanaged queues, or define multiple subscriptions on the one queue. The next example,, demonstrates how to combine subscriptions with an unmanaged subscription queue.
Note: The compact coding style is intended for readability not production use. There are some additional comments to make about the declarations in this example.
- MQHOBJ Hobj = MQHO_NONE;
- We cannot explicitly open a non-durable managed subscription queue to receive publications, but we do need to allocate storage for the object handle the queue manager returns when it opens the queue for you. It is important to initialize the handle to MQHO_OBJECT. This indicates to the queue manager that it needs to return a queue handle to the subscription queue.
- MQSD sd = {MQSD_DEFAULT};
- The new subscription descriptor, used in MQSUB.
- MQCHAR48 qName;
- Although the example doesn't require knowledge of the subscription queue, the example does inquire the name of the subscription queue - the MQINQ binding is a little awkward in the C language, so you might find this part of the example useful to study.
There are some additional comments to make about the code in this example.
- strncpy(sd.ObjectName, topicName, MQ_Q_NAME_LENGTH);
- If topicName is null or blank (default value), the topic name is not used to compute the resolved topic string.
- sd.ObjectString.VSPtr = topicString;
- Rather than solely use a predefined topic object, in this example the programmer provides a topic object and a topic string, that are combined by MQSUB. Notice the topic string is a MQCHARV structure.
- sd.ObjectString.VSLength = MQVS_NULL_TERMINATED;
- An alternative to setting the length of a MQCHARV field.
- sd.Options = MQSO_CREATE | MQSO_MANAGED | MQSO_NON_DURABLE | MQSO_FAIL_IF_QUIESCING;
- After defining the topic string, the sd.Options flags need the most careful attention. There are many options, the example specifies only the most commonly used ones. The other options use the default values.
- As the subscription is non-durable, that is, it has a lifetime of the open subscription in the application, set the MQSO_CREATE flag . We can also set the (default) MQSO_NON_DURABLE flag for readability.
- Complementing MQSO_CREATE is MQSO_RESUME. Both flags can be set together; the queue manager either creates a new subscription or resumes an existing subscription, whichever is appropriate. However, if you do specify MQSO_RESUME you must also initialize the MQCHARV structure for sd.SubName, even if there is no subscription to resume. Failure to initialize SubName results in a return code of 2440: MQRC_SUB_NAME_ERROR from MQSUB. Note: MQSO_RESUME is always ignored for a non-durable managed subscription: but specifying it without initializing the MQCHARV structure for sd.SubName does cause the error.
- In addition there is a third flag affecting how the subscription is opened, MQSO_ALTER. Given the correct permissions, the properties of a resumed subscription are changed to match other attributes specified in MQSUB. Note: At least one of the MQSO_CREATE, MQSO_RESUME and MQSO_ALTER flags must be specified. See Options (MQLONG). There are examples of using all three flags in Example 3: Unmanaged MQ subscriber.
- Set MQSO_MANAGED for the queue manager to manage the subscription for you automatically.
- sd.ObjectString.VSLength = MQVS_NULL_TERMINATED;
- Optionally, omit setting the length of MQCHARV for null terminated strings and use the null terminator flag instead.
- sd.ResObjectString.VSPtr = resTopicStr;
- The resulting topic string is echoed in first printf in the program. Set up MQCHARV ResObjectString for IBM MQ to return the resolved string back to the program. Note: resTopicStringBuffer is initialized to nulls in memset(resTopicStr, 0, sizeof(resTopicStrBuffer)). Returned topic strings do not end with a trailing null.
- sd.ResObjectString.VSBufSize = sizeof(resTopicStrBuffer)-1;
- Set the buffer size of the sd.ResObjectString to one less than its actual size. This prevents overwriting the null terminator that is provided, in case the resolved topic string fills the entire buffer. Note: No error is returned if the topic string is longer than sizeof(resTopicStrBuffer)-1. Even if VSLength > VSBufSiz the length returned in sd.ResObjectString.VSLength is the length of the complete string and not necessarily the length of the returned string. Test sd.ResObjectString.VSLength < sd.ResObjectString.VSBufSiz to confirm the topic string is complete.
- MQSUB(Hconn, &sd, &Hobj, &Hsub, &CompCode, &Reason);
- The MQSUB function creates a subscription. If it is non-durable we are probably not interested in its name, though we can inspect its status in IBM MQ Explorer. We can provide the sd.SubName parameter as input, so you know what name to look for; you obviously have to avoid name clashes with other subscriptions.
- MQCLOSE(Hconn, &Hsub, MQCO_REMOVE_SUB, &CompCode, &Reason);
- Closing both the subscription and the subscription queue is optional. In the example the subscription is closed, but not the queue. The MQCLOSE MQCO_REMOVE_SUB option is the default in this case anyway as the subscription is non-durable. Using MQCO_KEEP_SUB is an error. Note: the subscription queue is not closed by MQSUB, and its handle, Hobj, remains valid until the queue is closed by MQCLOSE or MQDISC. If the application terminates prematurely, the queue and subscription are cleaned up by the queue manager sometime after application termination.
Parent topic: Writing subscriber applications
Related concepts
- Example 1: MQ Publication consumer
- Example 3: Unmanaged MQ subscriber
- Writing publisher applications