Request-response pattern with worker queues in RabbitMQ - c#

I'm using RabbitMQ for the following scenario. When a user uses a premium search feature, I send a message via RabbitMQ to one of a few server instances. They run the same routine (DB queries and billing). I want to make sure I don't process the same message more than once.
I've come across this great tutorial but the exchange type presented in it is "Topic", which does not work for me, because I process the same message more than once.
How can I implement the request-response pattern with worker queues in RabbitMQ so that each message is handled only once and there's load balancing?

Anton Gogolev's comment above is correct. You cannot guarantee a message will be processed only once, for many reasons. But, this is often a requirement of systems - to only produce the desired result once.
The way to do that is through idempotence - the idea that no matter how many times a given message is processed, it will only make the desired change once.
There are a lot of ways to do this. One simple example is to use a shared database that tracks which messages have been processed. When you receive a message, you check to see if it has been processed already. If not, you process it. If it has, you just ignore it and move on.
In your case, if you are doing request/response and want load balancing, you probably want multiple consumers on the same queue. You could have 2 or 10 or 300 instances of your request handler listening to the same queue, and you won't have too much worry about duplicate processing.
RabbitMQ will send a given message to a single consumer. It will wait for that consumer to say it is done processing, or if the consumer crashes or rejects the message, it will requeue the message for another consumer to try again.
In this way, you will generally have only 1 request handler per request. But it will always be possible for more than one to handle the same message, which is why idempotence is important.
Regarding the use of a topic exchange vs any other type of exchange - it doesn't make much difference. There will always be the possibility of more than one queue receiving the message that you are sending, because you can have multiple queues bound to the same exchange with the same binding keys.

Related

Mixing of Pub/Sub with workqueues in RabbitMQ

I am evaluating using RabbitMQ as message queue/message bus and have been looking at the example tutorials on the RabbitMQ page.
I am looking for a specific scenario not covered by the tutorials and I am not sure if and how it would be possible to do via RabbitMQ.
The setup:
Let's assume I got a service, let's call it "purchase orders" and I have to other services called "logistics" and "accounting".
When an order is sent, I want to send it as a message via RabbitMQ.
There 2 "account" and 3 "logistic" services
What would be the correct way to ensure that "account" and "logistic" will process the message only once? Using pub/sub will cause the messages to be processed twice (account) or trice (logistics) if i understand it correctly.
With work queues and prefetch=1 it would assure that only one gets it, but I have 2 services and want each type of service to get one.
Is there a way to combine both and have a work queues for each of the service, without sending 2 separate events/messages to two different exchanges?
Using pub/sub will cause the messages to be processed twice (account) or trice (logistics) if i understand it correctly.
you probably have 1 queue per worker, based on your description, and you are routing the message to all worker queues. therefore, each worker gets a copy of the message, because you routed the message to all of the queues.
what you want is a single "account" queue and a single "logistic" queue. you will have multiple account services reading from the single account queue; same for the logistic service / queue.
setting prefetch=1 is important as well. this prevents you from reading too many messages in to a single worker, at once.
Is there a way to combine both and have a work queues for each of the service, without sending 2 separate events/messages to two different exchanges?
yes - don't use a fanout exchange. use a topic or direct exchange, and use multiple routing keys to route a single message to both the account and logistics queues.
What would be the correct way to ensure that "account" and "logistic" will process the message only once?
there is no way to guarantee this, 100%. at some point, even with a proper setup like I've described, you will have a network failure or a worker crash or some other problem and a message will get processed twice. you have to account for this in you design, using some form of idempotence in your message processing.
hope that helps!

How do I send lots of messages over NServiceBus without locking the Queue?

So I was doing some performance evaluations of NServiceBus and I realized that it behaves very oddly if you try to send say 1000 messages all at the same time... It actually sends them all async (which is fine) but it locks the queue from the handler. The result is the handler can not process any messages until the senders has completed sending all of there.
The behavior shows up in two slightly different ways.
Inside a Handler if you do a lot of sending, it looks like the receiving queue is locked until the handler completes (so say you add a thread sleep between each send, the receiver won't start handling messages until the Handler completes.
If I just send the message from a newed up Bus then a small sleep breaks the relationship, but if I just send say 1000 messages all at "once" the handler won't get the first one until after the last one is written, even though each one (at that point) should be a seporate call.
Is there an undocumented strategy here to batch send or something else going on... I understand you wouldn't "want" to do this normally, but understanding what happens during a Send from a handler, or a batch send from a normal BUS is pretty important to know ;-).
NServiceBus message handlers, by default, run wrapped in a TransactionScope. The processing of a message, any updates you do to your business data and any send of new messages will either complete or roll back together. This is what transactional messaging is all about.
If you send 1000 messages in a message handler, then it will not complete until the underlying messaging infrastructure has received all of them successfully. This can take some time, depending on your hardware.
If you want to opt out of this safe-by-default approach, there are several things you can do. You can disable transactional handling for your NServiceBus endpoint, or you can just suppress the ambient transaction scope when sending the messages. Notice however that you no longer have any transactional guarantees, so if you get an exception after sending 500 of those 1000 messages those 500 will be sent, while 500 will not.
One of my teams strategy for this is to try to break down a large batch into smaller batches, and then have a handler that receives those smaller batches and pushes out a individual events for each one.
Scenario: We have an endpoint that reads a database log file and pushes out a "TransactionOccurred" event for each line of the log file. We then read the log file again after a 10 second timeout and push out another batch of messages.
So, instead of pushing out 5K messages in one handler, we broke it down into 5 messages of 1K a piece and sent a command of that. Then we had a handler that received the 1K batch message, looped through and published out an individual event for each message.
The issue came in around doing a "publish" for 5K messages because there were several events being published and each one had a different set of subscribers with queues on the same server and remote servers which slowed the system down.
With this strategy we were also able to turn the MaximumConcurrencyLevel up a little to process multiple messages at one time and were able to get a higher throughput.
We have done this on a handful of endpoints and each one is a little different regarding the batch size and the MaximumConcurrencyLevel value. I'd recommend getting a control set of 50-100K messages and moving these values around a little to what is the most optimal for your situation.

Queuing in OneWay WCF Messages using Windows Service and SQL Server

I need to implement a queuing mechanism for WCF service requests. The service will be called by clients in a one-way manner. These request messages should be stored in a SQL Server database and a Windows Service queues the messages. The time at which the requests are processed will be configurable. If there happens error in processing the message, it need to be retried up to 100 times and if still fails it need to be terminated.
Also there should be a mechanism to monitor the number of transaction made on a day and number of failures.
QUESTIONS
If I were using MSMQ, clients could have forwarded the message to queue without knowing the service endpoint. But I am using SQL Server to store the request messages. How the clients can put the requests to SQL Server?
Is the solution feasible? Do we have any article/book that explains how to implement the above?
What are the steps to prevent service and client reaching faulted state in this scenario?
What is the best method to store incoming message to database?
What is the best method to implement retry mechanism? Anything already exist so that I don't have to reinvent the wheel?
Is there any book/article that explains this implementation?
NOTES
Content of the message will be complex XML. For example Travel expense items of an employee or a list of employees.
READING
Logging WCF Request to Database
Guaranteed processing of data in WCF service
MSMQ vs. SQL Server Service Broker
Is it possible to persist and then forward WCF messages to destination services?
WCF 4 Routing Service - protocol bridging issue
https://softwareengineering.stackexchange.com/questions/134605/designing-a-scalable-and-robust-retry-mechanism
Integrating SQL Service Broker and NServiceBus
Can a subscriber also publish/send message in NServiceBus?
I'm a DBA, so that flavors my my response, but here's what I'd do:
If you're using SQL 2005+, use Service Broker to store the messages
in the database rather than storing them in a table. You get a
queueing mechanism with this, so you can get rid of MSMQ. You'll also have a table, but it's just going to store the conversation handle (essentially, a pointer to the message) along with how many times it attempted this message. Lastly, you'll want some sort of a "dead letter box" where messages that reach your retry threshold go.
In your message processing code, do the following:
Begin a transaction
Receive a message off of the queue
If the retry count is greater than the threshold, move it to the dead letter box and commit
Increment the counter on the table for this message
Process the message
If the processing succeeded, commit the transaction
If the processing failed, put a new message on the queue with the same contents and then commit the transaction
Notice that there aren't any planned rollbacks. Rollbacks in Service Broker can be bad; if you rollback 5 times without a successful receive, the queue will become disabled for both enqueuing and dequeuing. But you still want to have transactions for the case when your message processor dies in the middle of processing (i.e. the server crashes).
1. If I were using MSMQ, clients could have forwarded the message to queue without knowing the service endpoint.
Yes - but they would need to know the MSMQ endpoint in order to send their message to the queue.....
But I am using SQL Server to store the request messages. How the clients can put the requests to SQL Server?
The clients won't put their requests into SQL Server - that's what the service on the server will do. The client just call a service method, and the code in there will store the request into the SQL Server table.
2. Is the solution feasible? Do we have any article/book that explains how to implement the above?
Sure, I don't see any big issue. The only point unclear to me right now is: how will the clients know their results?? Do they need to go get results from another service or something??
3. What are the steps to prevent service and client reaching faulted state in this scenario?
As always - just make sure your service code catches all exceptions and either handles them internally, or returns interoperable SOAP faults instead of .NET exceptions.
It sounds like what you want to do is similar to this:
In this case you can use netMsmqBinding between your service and your service consumers.
The only thing you won't get out of the box is the retrying. However if you make the queue transactional then this functionality can be implemented in your service code.
If there is a failure in your dequeue operation the message will not be removed from the queue. It will therefore be available for further dequeue attempts.
However, you would need to implement retry attempt threshold code which fails a message after a certain number of attempts.
I would suggest a different approach to the ones suggested here. If you are able to, I would consider the introduction of a messaging framework such as NServiceBus. It satifies many of the requirements that you have right out of the box. Let me try and address this in context of your requirements.
The service will be called by clients in a one-way manner.
All communication between endpoints in NServiceBus is one way. The underlying transport NServiceBus uses is MSMQ, so much like your WCF approach, your client is communicating with queues, rather than specific service endpoints.
These request messages should be stored in a SQL Server database and a Windows Service queues the messages.
If you wanted to store your request messages in a database then you can configure NServiceBus to forward all messages sent to your request processing endpoint to another "audit" queue, which you can use to persist to the database. This has the added benefit of separating your application logic from your auditing implementation.
The time at which the requests are processed will be configurable.
NServiceBus allows you to defer when a mesage is sent. Normally a message is sent via the Send method of a Bus instance - Bus.Send(msg). You can use The Defer method to send the message some time in the future eg. Bus.Defer(DateTime.Now.AddDays(1), msg); There's nothing more you really have to do, NserviceBus will handle the message once the specified time has been reached.
If there happens error in processing the message, it need to be retried up to 100 times and if still fails it need to be terminated.
By default, NServiceBus will enlist your message in a transaction as soon as your message leaves the queue. This ensures that in the event of failure that the message is rolled back to the originating queue. In such an event, NServiceBus will automatically try to reprocess the message a configurable number of times. The default being 5. You can of course set this to whatever you want, although I am not sure why you would want to set this to 100. At any rate, NServiceBus uses this setting to stop an endless loop of automatic retries. Once the limit has been reached the message is sent to an error queue where it sits until you fix whatever issues caused the exception or until you decide to push the message back to the queue for processing. Either way, you are assured that the message is never lost.
Also there should be a mechanism to monitor the number of transaction made on a day and number of failures.
The beauty of using MSMQ as the transport is that performance monitoring can be a achieved at a infrastructure level. How your applications perform, can be measured by how long they sit in the queue. NServiceBus comes with performance monitors that track the length of time a message is in the queue and you can also add perf mons that come built into windows to track other activity. To monitor errors, all you need to do is check the number of messages in the error queue.
One of the main features of NServiceBus is reliability. WCF will only do so much for you, and then you are on your own. That's a lot of code, complexity and frankly hugely error prone. The things I have described here are all standard features of NServiceBus and I have barely scratched the surface with all the other things that you can do with it. I recommend you check it out.

message broker consumer/producer with reassign when client goes down?

I am looking for a message broker API to use it with c#.
Normally the things are quite simple. I have a server that knows what jobs are to do and I have some clients that need to get these jobs.
And here are the special requirements I have:
If a client got a job but fails to answer within a specific time, then another client should do the work.
More than one queue and priorities
If possible it needs to work with big message queues (this way I could just load all jobs sometimes a month and forget about it
secured communications would be good.
API for talking with the broker from c#. How much work is done? What is still to do?
Delete some jobs...
If available replication to another broker would be good.
The broker needs to run on windows
What is not an issue:
low latency (there is no problem when a message needs minutes)
Do you know such a message broker that is free to use?
RabbitMQ and several other AMQP implementations satisfy most of (if not all of) these requirements.
RabbitMQ allows clients to acknowledge receipt and/or processing of messages. As per http://www.rabbitmq.com/tutorials/amqp-concepts.html#message-acknowledge:
If a consumer dies without sending an acknowledgement the AMQP broker
will redeliver it to another consumer or, if none are available at the
time, the broker will wait until at least one consumer is registered
for the same queue before attempting redelivery.
Many queues (and in fact many brokers) are supported, in a variety of different configurations
It scales particularly well, even for very large message queues: http://www.rabbitmq.com/faq.html#performance
Encryption is supported: http://www.rabbitmq.com/faq.html#channel-encryption
There is a .NET Client Users Guide and API docs: http://www.rabbitmq.com/documentation.html
There is live failover if a broker dies: http://www.rabbitmq.com/clustering.html
It runs on Windows, Linux, and probably anything else that has an Erlang implementation

Ensure / Verify message delivery using MSMQ (C#)

How do you 'verify' that a message sent using MSMQ to a private local queue was actually delivered? I'm especially thinking of a scenario where the listener (a C# service in my case) is not running and therefore delivery can't be successful.
You can only guarantee that it can get to the queue without taking extra steps. To deal with the "not running receiver" scenario, you would need to code the receiver to send a message back to the server when it processes the message. The original sender would be responsible for tracking the sent messages and verifying that the client has recieved them.
That's one of the decisions you should be taking when deciding whether or not to use MSMQ as opposed to a remoting or a web service scenario. For example, we had a project used for notifying all of our retail locations when an emergency occurred (such as a product recall/food safety issue.) We needed to know immediately if the store's listener was running so we chose remoting, and when the sender received an error indicating one of the listeners was not listenting, we would need to pick up the phone and call.
Just something to keep in mind.
Edit - clarification
I was really giving out two options above.
Code the client to send a message back to the sender when it receives a message.
Use another option, such as remoting, where you can detect if the client is running and receives the message.
It's always sent to the queue.
If your service isn't running to receive it, it just sits there, waiting patiently, until someone receives it.
You know it's been sent to the queue because .Send() returns without crashing.
You can probably pull this info out using administrative queues
When you send a message you can specify the AcknowledgeType which will allow you find out (through positive or negative acknowledgement) whether the message reached the queue and/or was received from the queue. Acknowledgements are sent as messages, by MSMQ, to the AdministrativeQueue so make sure you assign that property on the Message object.
You can check the administrative queue for acknowledgements by correlation ID which is ID of the original message.

Categories

Resources