EasyNetQ/RabbitMQ - Publishing a message based on topic - c#

I have created a subscriber in EasyNetQ/RabbitMQ with a topic. I think I have atleast because I can see that there is a binding under a queue name. It looks like the following :
The Queue name itself is a random GUID. But I don't think this matters.
However when I try and publish a message via EasyNetQ like so :
await _bus.PublishAsync(new Message<byte[]>(memoryStream.ToArray()), "QueueCallback");
The message never gets published onto the above queue.

Worked this out.
I was publishing inside a message wrapper, however I was subscribing as a byte array only. Even if the routing key is the same, if the object type is not an exact match it will never be routed.

Related

Apache NMS IBytesMessage has a prefix after dequeuing

I've tried my best to figure this out, but I'm guessing my inexperience with Dotnet/C# and message queues is showing through.
The problem
In a nutshell the situation I'm dealing with is, I have two projects.
The first project is a legacy Dotnet project using the Apache NMS library to consume messages from an ActiveMQ queue.
The queue is normally connected in production via SSL, but developing locally I have connected via TCP which all works fine and actively connects & dequeues as expected.
Once the messages are dequeued they are deserialised using the JsonConvert DeserializeObject method.
The second project is a NodeJS project which I've created to put messages onto the queue.
The messages are just a simple object, stringified to JSON.
I'm using the AMQP Rhea npm package to connect and send the messages, in AMQP format.
This again all works fine and the messages are enqueued as expected.
The problem is when I come to deserialising the message pulled from the queue.
There's an exception because it encounters a prefix to my JSON message - I have no idea where the prefix comes from.
I have a creeping suspicion it's because there's a clash between the protocols I'm using and that's causing the issue, but before I find myself in that particular rabbit hole - or just resorting to using a shaky method of removing the prefix - I'm hoping one of you with more experience can help point me in the right direction.
Code
Here's a couple of snippets of the offending C#:
This is how I'm dequeueing the messages:
string dequeuedMessage = string.Empty;
List<string> messages = new List<string>();
IMessage message = _consumer.Receive(waitForMessage);
if (message is ITextMessage || message is IBytesMessage)
{
dequeuedMessage = (message is ITextMessage) ? (message as ITextMessage).Text : Encoding.UTF8.GetString((message as IBytesMessage).Content);
messages.Add(dequeuedMessage);
}
else
break;
What's interesting is the message always comes through as type IBytesMessage, not what the previous author was expecting (ITextMessage), which is why I'm having that creeping suspicion.
And this is how I'm deserialising the message:
private IMessage BuildMessageObject(string message)
{
IMessage convertedMessage = JsonConvert.DeserializeObject<QueueMessage>(message);
return convertedMessage;
}
Here's a look at the prefix:
\0SpE\0SsE\0Sw\xb1\0\0\x01\xac{"Message":"Message Content Snipped for Brevity"}
It appears to always be the same, so maybe it means something to someone.
What I've Tried & Expectations
To quickly debug, I tried connecting to the queue in the Dotnet project using AMQP, but it appears that the Apache NMS package doesn't support this.
I'm not in a position to completely rewrite the connection with another package either.
I've also written something to dequeue the message in my Node app and I get the JSON back without the prefix, but this connects with the AMQP protocol which may be why?
Thanks for any help.
Edit: I should add that I'm using ActiveMQ Classic and not Artemis.
Answering my own question, it appears it is an issue with the amqp/rhea package and using the AMQP protocol as I suspected.
The problem, without running into details I can't fully explain, is that the message from the queue has been encoded and the message body includes that encoding.
The NMS library uses ActiveMQ's native OpenWire protocol.
I'm probably going to have to resolve this by moving from using the amqp/rhea package and trying to find an openwire equivalent - which is preferable than trying to find an AMQP equivalent for the Dotnet project.
Edit:
As it turns out, the rhea package is sufficient to solve the problem.
In sending the message body, I've instead created it as a Buffer instead of type Message:
const messageAsBuffer = Buffer.from(message);
sender.send(messageAsBuffer, undefined, 1);
where undefined can be a message tag and 1 can be any integer that is not 0, specifying the message is not in AMQP format.

How to read retained messages for a Topic

I have a web application that publishes messages to a topic then several Windows services that subscribe to those topics, some with multiple instances. If the services are running when the messages are published everything works correctly but if they are not then the messages are retained on the queue(s) subscribing to that topic but aren't read when the services start back up.
The desired behavior-
When a message is published to the topic string MyTopic, it is read
from the MyTopicQueue only once. I use some wildcard topics so each message is sent to multiple queues, but multiple instances of a services subscribe to the same topic string and each message should be read by only of those instances
If the subscribers to the MyTopic topic aren't online when the message is published then the messages are retained on MyTopicQueue.
When the Windows services subscribing
to a particularly topic come back on line each retained message is
read from MyTopicQueue by only a single subscriber.
I've found some [typically for IBM] spotty documentation about the MQSUBRQ and MQSO_PUBLICATIONS_ON_REQUEST options but I'm not sure how I should set them. Can someone please help figure out what I need to do to get my desired behavior? [Other than switching back to RabbitMQ which I can't do though I'd prefer it.]
My options:
private readonly int _openOptions = MQC.MQSO_CREATE | MQC.MQSO_FAIL_IF_QUIESCING | MQC.MQSO_MANAGED;
private readonly MQGetMessageOptions _messageOptions = new MQGetMessageOptions()
Code to open the Topic:
_topic = _queueManager.AccessTopic(_settings.TopicString, null,
MQC.MQTOPIC_OPEN_AS_SUBSCRIPTION, _openOptions);
The line of code that reads from the topic (taken from a loop):
_topic.Get(mqMessage, _messageOptions);
If you want the messages to accumulate while you are not connected you need to make the subscription durable by adding MQC.MQSO_DURABLE. In order to be able to resume an existing subscription add MQC.MQSO_RESUME in addition to MQC.MQSO_CREATE.
Be careful with terminology, what you are describing as retained messages is a durable subscription.
Retained publications are something else were MQ can retain one most recently published message on each topic and this message will be retrieved by new subscribers by default unless they use MQSO_NEW_PUBLICATIONS_ONLY to skip receiving the retained publication.
MQSO_PUBLICATIONS_ON_REQUEST allows a subscriber to only receive retained publications on request, it will not receive non-retained publications.
If you want multiple consumers to work together on a single subscription you have two options:
Look at shared subscribers in XMS.NET, look at the CLONESUPP property.
Create a one time durable subscription to a queue on the topics you want consumed, then have your consumers directly consume from the queue not a topic.

ActiveMQ access to previously published data on subscription

We're using ActiveMQ locally to transfer data between 5 processes that turn simultaneously.
I have some data I need to send to a process, both at runtime (which works perfectly fine), but also a default value on start. Thing is it is published when the process starts, it just doesn't read because it wasn't subscribed to the topic at the time the data was sent.
I have multiple solutions : I could delay the first publishing for a moment so that the process has time to launch (which doesn't seem very appealing) ; or is there a way to send all stored previously non-treated messages to some process that just subscribed ?
I'm coding in C#.
I don't have any experience with ActiveMQ, but other message system usually have an option which marks the subscription as persistent, which means that; after the first subscription; the message queue itself checks if a certain message is delivered to that system and retries with a timeout. In this scenario you need to start the receiver at least 1 time.
If this is not an option and you want to plug in receiver afterwards, you might want to consider a setup of your messages which allows you to retrieve the full state, i.e. if you send total-messages instead of differential- messages.
After a little google, I came upon this definition durable subscribers, I hope this helps:
See:
http://activemq.apache.org/how-do-durable-queues-and-topics-work.html
and
http://activemq.apache.org/manage-durable-subscribers.html
since you are using C# client i don't konw if this is supported
topic = new ActiveMQTopic("TEST.Topic?consumer.retroactive=true");
http://activemq.apache.org/retroactive-consumer.html
So, another solution is to configure this behavior on the broker side by adding that to the activemq.xml and restart :
The subscription recovery policy allows you to go back in time when
you subscribe to a topic.
<destinationPolicy>
<policyMap>
<policyEntries>
<policyEntry topic=">" >
<subscriptionRecoveryPolicy>
<timedSubscriptionRecoveryPolicy recoverDuration="10000" />
<fixedCountSubscriptionRecoveryPolicy maximumSize="10000" />
</subscriptionRecoveryPolicy>
</policyEntry>
</policyEntries>
</policyMap>
</destinationPolicy>
http://activemq.apache.org/subscription-recovery-policy.html
I went around the issue by sending a message from each process when they're launched back to the main one, and then only sending the info I needed to send.

Why is message put into a dead-letter queue (MSMQ)?

Preamble:
I have a web application, which sends MSMQ messages (with UseDeadLetterQueue = true) from time to time. I can also see that some of those messages are put into a system dead letter queue. However, I can't see the failure reason directly from "Computer Management" console.
I found the following resource:
https://msdn.microsoft.com/en-us/library/ms789035(v=vs.110).aspx,
which allows to check message status and failure. But it's usable only in WCF scope (as it uses OperationContext).
Basically checking message status and failure reason is what I need, but how can I configure a WCF service to listen to a dead-letter queue and track all the messages put inside, regardless of sender?
Or is there any other (non-WCF) way to get reason of why specific message was put into a dead letter queue?
The linked article you found tells you how to create a WCF service that takes messages off the DLQ. Note that it tells you you must use AddressFilterMode = AddressFilterMode.Any to pull all messages off regardless of sender.
Note: by the time the message ends up on the DLQ, you will not have information about the reason this occurred. Regardless of whether or not you're using WCF that information isn't stored in the queue.
If for example your recipient is a WCF listener using the MSMQ binding any exception thrown will cause the message to fail to get delivered. MSMQ will retry for a while and then eventually give up and put the message in the DLQ. So if you wanted to know the original reason you need to add some tracing in your WCF service to catch and trace thrown exceptions.

Read message body (raw xml) from MSMQ using Nservice bus before Handle() is called

Is There any way I can read raw xml message from MSMQ using NService bus before it parses it to corresponding class object.
I am getting message in Handle(Class obj). This is working fine but I want to log the xml from raw message body which NService parses to class object .
Have a look at transport message mutators. You'll be able to inspect both the Body and Headers of the message
#Chris-Bednarski's answer is correct, but I wanted to add that NServiceBus has auditing built-in which takes the complete messages and passes it on to another queue, so you don't have to do that yourself.
As of version 4, there is another process which feeds off of that queue and persists those messages into RavenDB as well as a UI (called ServiceInsight) that enables you to see everything that flowed through your system. You can find it here:
http://particular.net/ServiceInsight

Categories

Resources