What is a temporary queue?
Temporary queues are destinations with a scope limited to the connection that created it, and are removed on the server side as soon as the connection is closed. They are typically used for synchronous messaging (request/reply communication model). Their main advantage is that no queue management to provide unique destination names is required, because their uniqueness is provided by the server, and queues are removed automatically after use.
Use cases for temporary queues
The article Designing Messaging Applications with Temporary Queues by Thakur Thribhuvan shows a typical use case. In his example, many clients send messages with healthcare system information to a static request queue destination, and pass the identity of their individual temporary queue in the ReplyTo header of the message. The recipient of the message processes incoming messages in the static request queue, and sends a reply to the temporary queue in the ReplyTo header. The originating client then consumes the reply from the temporary queue.
The author summarizes: “In this configuration, temporary destinations can be viewed as analogous to callbacks in synchronous processing, i.e., when the callee wants to reach out to the caller in a decoupled way, without the caller and callee having to know about each other in advance.”
The unit test for temporary queues in the Habari Client for RabbitMQ 1.5 demonstrates the interaction between a ‘client’ and a ‘server’ using a static queue for the requests and temporary queues for the replies.
The server code creates a static request queue (ServerRequestQueue) and a consumer for the request messages (RequestConsumer). The server then starts receiving requests (shown later, we first need to see the client side).
// SERVER: start a consumer waiting for request messages ServerRequestQueue := Session.CreateQueue('StaticRequestQueue'); RequestConsumer := Session.CreateConsumer(ServerRequestQueue);
The client creates a destination object for the static request queue (ClientRequestQueue) and a message producer for the requests (RequestProducer). The client also a creates the temporary queue object (ClientTempQueue) and a consumer for the server response (ResponseConsumer).
// CLIENT: prepare a "normal" destination queue ClientRequestQueue := OutSession.CreateQueue('StaticRequestQueue'); RequestProducer := OutSession.CreateProducer(ClientRequestQueue); // CLIENT: create a temporary queue for responses ClientTempQueue := OutSession.CreateTemporaryQueue; // create a consumer for response messages ResponseConsumer := OutSession.CreateConsumer(ClientTempQueue);
Now the client creates and sends a request (RequestMsg), which also specifies the temporary queue in the ReplyTo header:
// CLIENT: send message and specify a reply queue RequestMsg := OutSession.CreateTextMessage('request'); // pass the temp queue name in the message header RequestMsg.JMSReplyTo := ClientTempQueue; // send it RequestProducer.Send(RequestMsg);
The server runs a receive loop to consume requests from the static request queue:
// SERVER: get the request RequestMsg := RequestConsumer.Receive(100); if RequestMsg <> nil then begin // ... process the request end
When the server completed the message processing, it sends the response back to the client:
// SERVER create reply queue based on message reply-to and send the response ResponseQueue := Session.CreateQueue((RequestMsg.JMSReplyTo as IQueue).QueueName); ResponseProducer := Session.CreateProducer(ResponseQueue); ResponseMsg := Session.CreateTextMessage('response'); ResponseProducer.Send(ResponseMsg);
Finally, the client receives the response message:
// CLIENT: receive the ResponseMsg from the temporary queue ReceivedResponseMsg := ResponseConsumer.Receive(100); if ReceivedResponseMsg <> nil then begin // ... process the response end else begin // error: no response received end;
This solution uses the terms “client” and “server” only to make the request/response communication clear: the client initiates the communication with a request, and the server responds. The “server” however is not necessarily a singular instance (a Delphi application). As the requests sent by the clients are stored in a single message queue on the message broker, it is possible to launch many identical Delphi applications, running the same logic shown above, to handle extra workload when needed.