Reusing IBM.WMQ.MQQueue object
We are using the .NET API to IBM's WebSphere MQ.
Creating the MQQueueManager object is clearly an expensive operation, and so we cache and reuse a pool of these objects.
Currently, for each request, we access the required queues:
//obtain queueManager from pool
IBM.WMQ.MQQueue requestQ= queueManager.AccessQueue(requestQName, mqOptions);
IBM.WMQ.MQQueue responseQ= queueManager.AccessQueue(responseQName, mqOptions);
and close them once done:
requestQ.Close();
responseQ.Close();
Is this best practice, or should we be also pooling and reusing the MQQueue objects (in addition to the queue manager)? AccessQueue() appears to be a cheap operation 开发者_C百科on the client.
The answer depends on your threading model and transactionality. In general, messaging clients should always use transactionality, even if that is only single-phase commit. The reason is that there are ambiguities of outcomes that can cause duplicate or lost messages otherwise. I've provided a much more detailed explanation of this in another answer.
The issue is that transactions are connection-scoped. When you COMMIT you do so for the entire connection. Using the same connection across several threads safely would preclude the use of transactions and thus expose the app to lost or duplicate messages. Since queue handles are only valid in the context of a particular connection, they inherit from your threading model and connection pool.
The most common model for a service provider application is to maintain a connection per-thread on the input queue and dynamically open/put/close the output queue. For example, in a single unit of work...
- Read the next request message
- Use the reply-to information to obtain the destination
- Open the reply-to queue
- Put the response
- Commit
- Destroy the reply-to destination object and thus close the reply-to queue
In this case the connections are not constantly rebuilt, nor is the input queue ever closed. However, it does require each thread to maintain a dedicated connection.
精彩评论