I'm new to the Azure Service Bus and am working on a proof of concept using Service Bus Queues, WebJobs, v2.5 of the Azure SDK and Visual Studio 2013
Enqueuing and de-queuing messages from the bus is pretty straightforward, but in order to implement a request-response pattern it looks like I need to use sessions, and that's where the wheels have come off.
Here's the proof-of-concept code from the WebJobs project. It requires that you create two service bus queues: test-request and test-response. The response queue must have Enable Sessions = true
class Program
{
private static string _azureServiceBusConnection;
static void Main()
{
_azureServiceBusConnection = ConfigurationManager.ConnectionStrings["AzureWebJobsServiceBus"].ConnectionString;
var host = new JobHost();
Task.Factory.StartNew(() => Run());
try
{
host.RunAndBlock();
}
catch (Exception ex)
{
Console.WriteLine("RunAndBlock() Unexpected {0}: {1}", ex.GetType().FullName, ex.Message);
throw;
}
}
private static async Task Run()
{
await Task.Delay(1000);
var request = QueueClient.CreateFromConnectionString(_azureServiceBusConnection, "test-request");
var response = QueueClient.CreateFromConnectionString(_azureServiceBusConnection, "test-response");
var sessionid = Guid.NewGuid().ToString();
MessageSession receiver;
try
{
receiver = response.AcceptMessageSession(sessionid);
}
catch (Exception ex )
{
Console.WriteLine("AcceptMessageSession() Unexpected {0}: {1}", ex.GetType().FullName, ex.Message);
throw;
}
var payload = new RequestModel {ID = Guid.NewGuid(), Delay = 1};
var message = new BrokeredMessage(payload) {ReplyToSessionId = sessionid};
try
{
request.Send(message);
}
catch (Exception ex)
{
Console.WriteLine("Send() Unexpected {0}: {1}", ex.GetType().FullName, ex.Message);
throw;
}
var receivedMessage = receiver.Receive(TimeSpan.FromSeconds(5));
if (receivedMessage != null)
{
// Request processed within the timeout period
var responseBody = receivedMessage.GetBody<RequestModel>();
Console.WriteLine("Inline response to {0}", responseBody.ID );
receivedMessage.Complete();
}
else
{
// Request processing timed out - should be handled by LocalResponseQueue WebJob (see below)
Console.WriteLine("ERROR: Response timed out.");
}
}
}
public class RequestModel
{
public Guid ID { get; set; }
public int Delay { get; set; }
}
public class RemoteSystemRequestQueue
{
// Simulates the processing of the request on a remote system
public static void ProcessQueueMessage([ServiceBusTrigger("test-request")] BrokeredMessage request, [ServiceBus("test-response")] out BrokeredMessage response)
{
// Wait for the prescribed delay, then bounce the request payload back via the response queue
var requestBody = request.GetBody<RequestModel>();
Console.WriteLine("Recieved Request {0}, delay={1}", requestBody.ID, requestBody.Delay);
Task.Delay(requestBody.Delay * 1000).Wait();
response = new BrokeredMessage(requestBody) {SessionId = request.ReplyToSessionId};
request.Complete();
Console.WriteLine("Completed Request {0}, delay={1}", requestBody.ID, requestBody.Delay);
}
}
public class LocalResponseQueue
{
// Should be called ONLY when the processing took longer than the timeout
public static void ProcessQueueMessage([ServiceBusTrigger("test-response")] BrokeredMessage message, TextWriter logger)
{
var msgBody = message.GetBody<RequestModel>();
Console.WriteLine("ResponseFactory Recieved Reply {0}", msgBody.ID);
}
}
When Enable Sessions = true on the test-response queue, the call to host.RunAndBlock() throws a System.InvalidOperationException with the message
It is not possible for an entity that requires sessions to create a non-sessionful message receiver
The output looks like this:
Found the following functions:
ServiceBusPoc.RemoteSystemRequestQueue.ProcessQueueMessage
ServiceBusPoc.LocalResponseQueue.ProcessQueueMessage
Executing: 'RemoteSystemRequestQueue.ProcessQueueMessage' because New service bus message detected on 'test-request'.
Recieved Request 4f000f8f-dd69-4909-9ec4-020fec12366c, delay=1
RunAndBlock() Unexpected System.InvalidOperationException: It is not possible for an entity that requires sessions to create a non-sessionful message receiver.
TrackingId:7836ac90-6920-4e6c-b7f1-cf648e2a17e5_G38_B10,TimeStamp:10/6/2015 12:37:05 PM
Note that the exception was thrown BEFORE the RemoteSystemRequestQueue object could complete processing the queued request
I presume from this that this means that WebJobs can't handle sessions (at least in the manner in which I'm using them)
Can anyone shed any light on this, or am I going to have to give up on WebJobs?
What version of the WebJobs SDK are you using? In our current v1.1.0 release (still prerelease) we've started opening up more options for ServiceBus configuration. See:
ServiceBusConfiguration
Custom MessagingProvider
You can basically now control more of the messaging details that were previously buried in the SDK internals. However, regarding full Session support, we do have this open issue that might be closer to your scenario. If so, and if you can't get things to work with the above, please add your scenario details to that issue. Thanks.
Related
My client is attempting to send messages to the receiver. However I noticed that the receiver sometimes does not receive all the messages sent by the client thus missing a few messages (not sure where the problem is ? Client or the receiver).
Any suggestions on why that might be happening. This is what I am currently doing
On the receiver side this is what I am doing.
This is the Event Processor
async Task IEventProcessor.ProcessEventsAsync(PartitionContext context, IEnumerable<EventData> messages)
{
foreach (var eventData in messages)
{
var data = Encoding.UTF8.GetString(eventData.Body.Array, eventData.Body.Offset, eventData.Body.Count);
}
}
This is how the client connects to the event hub
var StrBuilder = new EventHubsConnectionStringBuilder(eventHubConnectionString)
{
EntityPath = eventHubName,
};
this.eventHubClient = EventHubClient.CreateFromConnectionString(StrBuilder.ToString());
How do I direct my messages to specific consumers
I'm using this sample code from eventhub official doc, for sending and receiving.
And I have 2 consumer groups: $Default and newcg. Suppose you have 2 clients, the client_1 are using the default consumer group($Default), and client_2 are using the other consumer group(newcg)
First, after create the send client, in the SendMessagesToEventHub method, we need to add a property with value. The value should be the consumer group name. Sample code like below:
private static async Task SendMessagesToEventHub(int numMessagesToSend)
{
for (var i = 0; i < numMessagesToSend; i++)
{
try
{
var message = "444 Message";
Console.WriteLine($"Sending message: {message}");
EventData mydata = new EventData(Encoding.UTF8.GetBytes(message));
//here, we add a property named "cg", it's value is the consumer group. By setting this property, then we can read this message via this specified consumer group.
mydata.Properties.Add("cg", "newcg");
await eventHubClient.SendAsync(mydata);
}
catch (Exception exception)
{
Console.WriteLine($"{DateTime.Now} > Exception: {exception.Message}");
}
await Task.Delay(10);
}
Console.WriteLine($"{numMessagesToSend} messages sent.");
}
Then in the client_1, after create the receiver project, which use the default consumer group($Default)
-> in the SimpleEventProcessor class -> ProcessEventsAsync method, we can filter out the unnecessary event data. Sample code for ProcessEventsAsync method:
public Task ProcessEventsAsync(PartitionContext context, IEnumerable<EventData> messages)
{
foreach (var eventData in messages)
{
//filter the data here
if (eventData.Properties["cg"].ToString() == "$Default")
{
var data = Encoding.UTF8.GetString(eventData.Body.Array, eventData.Body.Offset, eventData.Body.Count);
Console.WriteLine($"Message received. Partition: '{context.PartitionId}', Data: '{data}'");
Console.WriteLine(context.ConsumerGroupName);
}
}
return context.CheckpointAsync();
}
And in another client, like client_2, which use another consumer group, like it's name is newcg, we can follow the steps in client_1, just a little changes in ProcessEventsAsync method, like below:
public Task ProcessEventsAsync(PartitionContext context, IEnumerable<EventData> messages)
{
foreach (var eventData in messages)
{
//filter the data here, using another consumer group name
if (eventData.Properties["cg"].ToString() == "newcg")
{
//other code
}
}
return context.CheckpointAsync();
}
This happens only when there are 2 or more Event Processor Host reading from same consumer group.
If you have event hub with 32 partitions and 2 event processor host reading from same consumer group. Then each event processor host will read from 16 partition and so on.
Similarly if 4 Event processor host parallelly reading from same consumer group then each will read from 8 partitions.
Check if you have 2 or more event processor host running on same consumer group.
I have tested your code and slightly modified it(different overload of EventProcessorHost constructor, and added CheckpointAsync after consuming the messages), and then did some tests.
By using the default implementation and default EventProcessorOptions(EventProcessorOptions.DefaultOptions) I can say that I did experience some latency when it comes to consuming messages, but all messages were processed successfully.
So, sometimes it seems like I am not getting the messages from the certain partition, but after a certain period of time, all messages arrive:
Here you can find the actual modified code that worked for me. It is a simple console app that prints to the console if something arrives.
string processorHostName = Guid.NewGuid().ToString();
var Options = new EventProcessorOptions()
{
MaxBatchSize = 1, //not required to make it working, just for testing
};
Options.SetExceptionHandler((ex) =>
{
System.Diagnostics.Debug.WriteLine($"Exception : {ex}");
});
var eventHubCS = "event hub connection string";
var storageCS = "storage connection string";
var containerName = "test";
var eventHubname = "test2";
EventProcessorHost eventProcessorHost = new EventProcessorHost(eventHubname, "$Default", eventHubCS, storageCS, containerName);
eventProcessorHost.RegisterEventProcessorAsync<MyEventProcessor>(Options).Wait();
For sending the messages to the event hub and testing I used this message publisher app.
I am learning Azure Events Hub. A simple application i have downloaded from this link https://learn.microsoft.com/en-us/azure/event-hubs/event-hubs-dotnet-standard-getstarted-send . But when i try to send message, its giving me this error:
10/23/2018 11:11:13 PM > Exception: Put token failed. status-code:
404, status-description: The messaging entity
'sb://demo.servicebus.windows.net/myTeam' could not
be found. TrackingId:[My Tracking ID],
SystemTracker:iot-bd-madness.servicebus.windows.net:IoT-BD-Madness,
Timestamp:10/23/2018 5:11:18 PM.
In Azure Event Hub Dashboard all incoming requests (sending from console app) are visible with chart. but those are all request actually failed when i tried in console application
N.B:the given connectionstring is not real
public class Program
{
private static EventHubClient eventHubClient;
private const string EventHubConnectionString = "Endpoint=sb://iot-bd-madness.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
private const string EventHubName = "Iot-Bd-Madness";
public static void Main(string[] args)
{
MainAsync(args).GetAwaiter().GetResult();
}
private static async Task MainAsync(string[] args)
{
// Creates an EventHubsConnectionStringBuilder object from a the connection string, and sets the EntityPath.
// Typically the connection string should have the Entity Path in it, but for the sake of this simple scenario
// we are using the connection string from the namespace.
var connectionStringBuilder = new EventHubsConnectionStringBuilder(EventHubConnectionString)
{
EntityPath = EventHubName
};
eventHubClient = EventHubClient.CreateFromConnectionString(connectionStringBuilder.ToString());
await SendMessagesToEventHub(100);
await eventHubClient.CloseAsync();
Console.WriteLine("Press any key to exit.");
Console.ReadLine();
}
// Creates an Event Hub client and sends 100 messages to the event hub.
private static async Task SendMessagesToEventHub(int numMessagesToSend)
{
for (var i = 0; i < numMessagesToSend; i++)
{
try
{
var message = $"Message {i}";
Console.WriteLine($"Sending message: {message}");
await eventHubClient.SendAsync(new EventData(Encoding.UTF8.GetBytes(message)));
}
catch (Exception exception)
{
Console.WriteLine($"{DateTime.Now} > Exception: {exception.Message}");
}
await Task.Delay(10);
}
Console.WriteLine($"{numMessagesToSend} messages sent.");
}
}
}
I ran into same problem. My EventHubName = "myeventhubname" was wrong. I passed the Event Hubs Namespace value - rounded in red. It gave error.
I changed it to value under Event Hub page left column -> click Entities -> Event Hubs
I used the name that was shown in the table rounded in green.
I am trying to write an integration / acceptance test to test some code in azure, the code in the question ATM simply subscribes to one topic and publishes to another.
I have written the test but it doesn't always pass, seems as though there could be a race condition in place. I've tried writing it a couple of ways including using OnMessage and also using Receive (example I show here).
When using OnMessage the test seemed to always exit prematurely (around 30 seconds), which I guess perhaps means its inappropriate for this test anyway.
My query concerning my example specifically, I assumed that once I created the subscription to the target topic, that any message sent to it I would be able to pickup using Receive(), whatever point in time that message arrived meaning, if the message arrives at the target topic before I call Receive(), I would still be able to read the message afterward by calling Receive(). Could anyone please shed any light on this?
namespace somenamespace {
[TestClass]
public class SampleTopicTest
{
private static TopicClient topicClient;
private static SubscriptionClient subClientKoEligible;
private static SubscriptionClient subClientKoIneligible;
private static OnMessageOptions options;
public const string TEST_MESSAGE_SUB = "TestMessageSub";
private static NamespaceManager namespaceManager;
private static string topicFleKoEligible;
private static string topicFleKoIneligible;
private BrokeredMessage message;
[ClassInitialize]
public static void BeforeClass(TestContext testContext)
{
//client for publishing messages
string connectionString = ConfigurationManager.AppSettings["ServiceBusConnectionString"];
string topicDataReady = ConfigurationManager.AppSettings["DataReadyTopicName"];
topicClient = TopicClient.CreateFromConnectionString(connectionString, topicDataReady);
topicFleKoEligible = ConfigurationManager.AppSettings["KnockOutEligibleTopicName"];
topicFleKoIneligible = ConfigurationManager.AppSettings["KnockOutIneligibleTopicName"];
//create test subscription to receive messages
namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString);
if (!namespaceManager.SubscriptionExists(topicFleKoEligible, TEST_MESSAGE_SUB))
{
namespaceManager.CreateSubscription(topicFleKoEligible, TEST_MESSAGE_SUB);
}
if (!namespaceManager.SubscriptionExists(topicFleKoIneligible, TEST_MESSAGE_SUB))
{
namespaceManager.CreateSubscription(topicFleKoIneligible, TEST_MESSAGE_SUB);
}
//subscriber client koeligible
subClientKoEligible = SubscriptionClient.CreateFromConnectionString(connectionString, topicFleKoEligible, TEST_MESSAGE_SUB);
subClientKoIneligible = SubscriptionClient.CreateFromConnectionString(connectionString, topicFleKoIneligible, TEST_MESSAGE_SUB);
options = new OnMessageOptions()
{
AutoComplete = false,
AutoRenewTimeout = TimeSpan.FromMinutes(1),
};
}
[TestMethod]
public void E2EPOCTopicTestLT50()
{
Random rnd = new Random();
string customerId = rnd.Next(1, 49).ToString();
FurtherLendingCustomer sentCustomer = new FurtherLendingCustomer { CustomerId = customerId };
BrokeredMessage sentMessage = new BrokeredMessage(sentCustomer.ToJson());
sentMessage.CorrelationId = Guid.NewGuid().ToString();
string messageId = sentMessage.MessageId;
topicClient.Send(sentMessage);
Boolean messageRead = false;
//wait for message to arrive on the ko eligible queue
while((message = subClientKoEligible.Receive(TimeSpan.FromMinutes(2))) != null){
//read message
string messageString = message.GetBody<String>();
//Serialize
FurtherLendingCustomer receivedCustomer = JsonConvert.DeserializeObject<FurtherLendingCustomer>(messageString.Substring(messageString.IndexOf("{")));
//assertion
Assert.AreEqual(sentCustomer.CustomerId, receivedCustomer.CustomerId,"verify customer id");
//pop message
message.Complete();
messageRead = true;
//leave loop after processing one message
break;
}
if (!messageRead)
Assert.Fail("Didn't receive any message after 2 mins");
}
}
}
As the official document states about SubscriptionClient.Receive(TimeSpan):
Parameters
serverWaitTime
TimeSpan
The time span the server waits for receiving a message before it times out.
A Null can be return by this API if operation exceeded the timeout specified, or the operations succeeded but there are no more messages to be received.
Per my test, if a message sent to the topic and then delivered to your subscription within your specific serverWaitTime, then you could receive a message no matter whether the message arrives at the target topic before or after you call Receive.
When using OnMessage the test seemed to always exit prematurely (around 30 seconds), which I guess perhaps means its inappropriate for this test anyway.
[TestMethod]
public void ReceiveMessages()
{
subClient.OnMessage(msg => {
System.Diagnostics.Trace.TraceInformation($"{DateTime.Now}:{msg.GetBody<string>()}");
msg.Complete();
});
Task.Delay(TimeSpan.FromMinutes(5)).Wait();
}
For SubscriptionClient.OnMessage, I assumed that it basically a loop invoking Receive. After calling OnMessage, you need to wait for a while and stop this method to exit. Here is a blog about the Event-Driven message programming for windows Azure Service Bus, you could refer to here.
Additionally, I found that your topicClient for sending messages and the subClientKoEligible for receiving a message are not targeted at the same topic path.
I am looking for callbacks related to add and read data in realm with xamarin.
Here i am fetching data from server and adding into realm , but i want an event where in i can notify UI that company data has been added to realm successfully and if any error comes i can show that too.
var content = await response.Content.ReadAsStringAsync();
Company company = JsonConvert.DeserializeObject<Company>(content);
Realm realm = Realm.GetInstance();
await realm.WriteAsync(tempRealm => {
tempRealm.Add(company);
});
in android native we have following function to execute any transaction in background and can notify for success and failure.
final Realm realm = Realm.getInstance(App.getRealmConfig());
realm.executeTransactionAsync(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
realm.copyToRealmOrUpdate(userResponseInfo.getCallInfoList());
}
}, new Realm.Transaction.OnSuccess() {
#Override
public void onSuccess() {
}
}, new Realm.Transaction.OnError() {
#Override
public void onError(Throwable error) {
}
});
Realm Xamarin uses the standard .NET mechanism of propagating errors from tasks, which is why you don't need a success and error callbacks. If an error occurred, an exception will be thrown that can be handled in a regular try-catch block:
try
{
var realm = Realm.GetInstance();
await realm.WriteAsync(temp => temp.Add(company));
// if control reaches this line the transaction executed successfully.
notifier.NotifySuccess();
}
catch (Exception ex)
{
// The transaction failed - handle the exception
notifier.NotifyError(ex.Message);
}
Lately, I've been trying to get the Reply-To pattern to work in Apache NMS /ActiveMQ and have been having problems sending messages to temporary queues using only the name of the temporary queue.
The project is dispatcher service which retrieves requests from the bus and sends them to another process/runtime (based on complex routing criteria) to process the request. This separate processor then uses the reply-to queue name and correlation ID to craft the response and sending it to the original requester on the same broker but a different connection.
The problem is that it appears you can only send to a temporary queue (or topic) if you have the IDestination object reference from the message's NMSReplyTo header. If that reference is lost, there is no way to send messages to a temporary queue (or topic) by simply using its name.
Illustrating this problem is this simple "Pong" service which listens on a message queue and issues a response to the requester using the contents of the NMS Reply-To header. It mimics dispatching the request to another process by simply calling the ProcessMessage(string,string) method.
using System;
using Apache.NMS;
namespace PongService
{
/// <summary>Simple request dispatcher which mimics dispatching requests to other workers in "The Cloud"</summary>
class PongService
{
static ISession session = null;
static IMessageProducer producer = null;
public static void Main(string[] args)
{
Uri connecturi = new Uri("activemq:tcp://localhost:61616");
Console.WriteLine("Connecting to " + connecturi);
IConnectionFactory factory = new NMSConnectionFactory(connecturi);
IConnection connection = factory.CreateConnection();
session = connection.CreateSession();
IDestination destination = session.GetQueue("PONG.CMD");
Console.WriteLine("Using destination: " + destination);
producer = session.CreateProducer(null);
IMessageConsumer consumer = session.CreateConsumer(destination);
connection.Start();
consumer.Listener += new MessageListener(OnMessage);
Console.WriteLine("Press any key to terminate Pong service . . .");
// loop until a key is pressed
while (!Console.KeyAvailable)
{
try { System.Threading.Thread.Sleep(50); }
catch (Exception ex) { Console.Error.WriteLine(ex.Message + "\r\n" + ex.StackTrace); }
} // loop
Console.Write("Closing connection...");
consumer.Close();
producer.Close();
session.Close();
connection.Close();
Console.WriteLine("done.");
}
/// <summary>Consumer call-back which receives requests and dispatches them to available workers in 'The Cloud'</summary>
/// <param name="receivedMsg">The message received on the request queue.</param>
protected static void OnMessage(IMessage receivedMsg)
{
// mimic the operation of passing this request to an external processor which can connect
// to the broker but will not have references to the session objects including destinations
Console.WriteLine("Sending request to an external processor");
ProcessMessage(receivedMsg.NMSReplyTo.ToString(), receivedMsg.NMSCorrelationID.ToString());
}
/// <summary>Models a worker in another process/runtime.</summary>
/// <param name="queuename">Where to send the results of processing</param>
/// <param name="crid">Correlation identifier of the request.</param>
protected static void ProcessMessage(string queuename, string crid)
{
ITextMessage response = session.CreateTextMessage("Pong!");
response.NMSCorrelationID = crid;
IDestination destination = session.GetQueue(queuename);
Console.WriteLine("Sending response with CRID of '" + crid + "' to " + queuename + "'");
try
{
producer.Send(destination, response);
}
catch (Exception ex)
{
Console.Error.WriteLine("Could not send response: " + ex.Message);
}
}
}
}
Now for the client. It simply creates a temporary queue, starts listening to it and then sends a request on the queue on which our "Pong" service is listening. The request message contains the IDestination of the temporary queue.
using System;
using System.Threading;
using Apache.NMS;
using Apache.NMS.Util;
namespace PongClient
{
class PongClient
{
protected static AutoResetEvent semaphore = new AutoResetEvent(false);
protected static ITextMessage message = null;
protected static TimeSpan receiveTimeout = TimeSpan.FromSeconds(3);
public static void Main(string[] args)
{
Uri connecturi = new Uri("activemq:tcp://localhost:61616");
Console.WriteLine("About to connect to " + connecturi);
IConnectionFactory factory = new NMSConnectionFactory(connecturi);
IConnection connection = factory.CreateConnection();
ISession session = connection.CreateSession();
IDestination temporaryDestination = session.CreateTemporaryQueue();
Console.WriteLine("Private destination: " + temporaryDestination);
IDestination destination = session.GetQueue("PONG.CMD");
Console.WriteLine("Service destination: " + destination);
IMessageConsumer consumer = session.CreateConsumer(destination);
consumer.Listener += new MessageListener(OnMessage);
IMessageProducer producer = session.CreateProducer(destination);
connection.Start();
// Send a request message
ITextMessage request = session.CreateTextMessage("Ping");
request.NMSCorrelationID = Guid.NewGuid().ToString();
request.NMSReplyTo = temporaryDestination;
producer.Send(request);
// Wait for the message
semaphore.WaitOne((int)receiveTimeout.TotalMilliseconds, true);
if (message == null)
{
Console.WriteLine("Timed-Out!");
}
else
{
Console.WriteLine("Received message with ID: " + message.NMSMessageId);
Console.WriteLine("Received message with text: " + message.Text);
}
}
protected static void OnMessage(IMessage receivedMsg)
{
message = receivedMsg as ITextMessage;
semaphore.Set();
}
}
}
The Pong process seems to operate correctly, only it winds-up making a completely new, separate queue from the one specified in the Reply-To header.
Here are the versions of the technologies involved:
Apache.NMS.ActiveMQ v1.5.1
Apache.NMS API v1.5.0
ActiveMQ 5.5.0
C# .NET 3.5
This question is related to this post which describes a similar problem. Hopefully these examples will help clarify the issue in that request as well.
Any help or insight to the solution would be greatly appreciated.
You're not actually setting the reply-to header in the request message from the PongClient.
Try this:
ITextMessage request = session.CreateTextMessage("Ping");
request.NMSCorrelationID = Guid.NewGuid().ToString();
request.NMSReplyTo = temporaryDestination;
producer.Send(request);
You need to use the IDestination you are passed.
Calling
IDestination destination = session.GetQueue(queuename);
is a little evil. Under the covers it calls CreateTemporaryQueue() replaces the existing temporary queue with a new one of the same name without informing you.
I would recommend using a topic as a reply destination, and have your consumer filter based on the NMSCorrelationID. This is the implementation I have moved to after much frustration with temp queues. It actually has many advantages.
It cuts down on intensive resource usage on the server (no need to construct/deconstruct temp queues).
It allows you to use another consumer to monitor the response sent back (you will never be able to "peek" inside a temp queue).
And it is much more reliable because the topic can be passed via a logical name instead of a specific token ID (which you are losing across connections).