I see that RabbitTemplate.convertAndSend() declares to throw AmqpException. Will this exception always be thrown if publishing a message will be unsuccessful or should one take extra measures, for example, using correlationConvertAndSend() along with a RabbitTemplate.ConfirmCallback.
Publishing to RabbitMQ is asynchronous; you will only get an exception for immediate failures (such as can't connect to the broker).
Publisher confirms and returns are needed for guaranteed delivery.
Related
What exceptions which should be handled in application would MassTransit throw?
I am using MassTransit with RabbitMQ.
I am wondering what exceptions we should catch from MassTransit.
Do you have anything like API document. (Hope it describe about errors)
Here is a list of exceptions that MassTransit may throw:
MassTransit.MessageData.DecodeException: Thrown when the message body cannot be decoded.
MassTransit.MessageData.EncodingException: Thrown when the message body cannot be encoded.
MassTransit.MessageData.MissingContentTypeException: Thrown when the message does not have a content type.
MassTransit.MessageData.NotFoundException: Thrown when the message cannot be found in the message data store.
MassTransit.MessageData.OptimisticConcurrencyException: Thrown when the message data has been modified since it was last read.
MassTransit.MessageData.StoreException: Thrown when an error occurs while storing or retrieving the message data.
MassTransit.MessageData.TooLargeException: Thrown when the message size exceeds the maximum allowed size.
MassTransit.Pipeline.Filters.CircuitBreakerException: Thrown when the circuit breaker is open.
MassTransit.Pipeline.Filters.ConcurrencyException: Thrown when the filter concurrency limit is reached.
MassTransit.Pipeline.Filters.RetryException: Thrown when the filter retry limit is reached.
Note that this is not an exhaustive list and there may be other exceptions thrown by MassTransit depending on your specific implementation.
I would recommend reviewing the code and seeing if more exceptions have been added, and review if you need to catch them.
Remember exceptions are not Pokemon, you don't have to catch them all :)
https://github.com/MassTransit/MassTransit/search?q=throw&type=commits
I am working on RabbitMQ integration. I have a microservice which receives messages from other services. I am currently looking into how to handle messages which encounter exceptions during processing.
The scenario could be:
ServiceA sends message to engine's queue.
Engine processes the message received.
During processing, engine encountered an exception (say a NullPointerException)
Engine returns the message to ServiceA for reprocessing
ServiceA holds the message until the exception in the engine is resolved (resending to engine can be manually triggered)
I bumped into Spring AMQP documentation about Publisher Returns but I could not totally grasp the context. I would like to know how this works and if this could be a solution to address above item #4. Or is there other solution for this?
Thank you in advance!
For #4 on your list the solution is quite simple - don't acknowledge the message automatically, rather then when the processing is finished. In that way -
if the client (subscriber) dies (for whatever reason) during processing of the message then that message is re-queued (so sent to ServiceA for reprocessing in your case).
If you want to explicitly re-queue the message you could do negative acknowledgment (search for it here).
In any case of re-queuing (manual or automatic) you should be careful that the single message that causes subscribers to die doesn't end up being processed forever by subscriber(s), that is - make sure that the exception that happened during processing was a random and not a guaranteed event. Example for this would be a message containing invalid XML - you process it, see it's invalid, handle the exception and re-queue, but then again another (or the same) subscriber gets it, and handles the same exception since the content of the message and the XML inside it didn't change and so on...
I understand NServiceBus's retry mechanism to be primarily for connectivity problems or database deadlock problems, which is great and I love it for that.
However, I would like to configure NServiceBus' retry mechanism to not bother with a retry if the exception is typeof(ApplicationException). My code throws this kind of exception when there is a broken business rule (like a customer on hold), so no matter how many times this message is retried by NServiceBus' quick-retry mechanism, it will fail. This scenario requires that users take action on the data and then use ServiceInsight to re-queue the message for processing.
Can this be done?
I would reconsider using your application logic to inform users about this type of errors using Reply or Return in your handler, that should be located in the catch (ApplicationException) section. Then users change the data and send the message again using your application, not ServiceInsight. In this case, do not re-throw the ApplicationException in your catch block and this will prevent NServiceBus from retrying your message handling.
While debugging my NServiceBus enabled application, I have certain messages that are reported in the console as "failed maximum number of times".
When I attach a debugger to the handler, everything is working as I would expect. The handler throws no exceptions.
The handler does however create an SQLTransaction, and is intentionally rolling the transaction back as part of the handling for some message scenarios. It seems to be that it is the messages that are getting transactions rolled back are the ones that are being reported as failed.
Is there some relationship between SQLTransactions and NServiceBus that would cause NServiceBus to recognize that a rollback has occurred?
I know that sounds unlikely, but cant think of anything else that might cause the message fail at this stage?
My guess (without seeing the exception error message) is that your error comes from handling SQL transactions manually.
If you're running NServiceBus with default settings, message handling occurs inside a .NET TransactionScope, also known as an "ambient transaction". It's likely that your SQL transaction gets enlisted in the ambient transaction, and thus your manually rolling back the transaction will result in an error.
The "idiomatic NServiceBus way" (at least of you're ok with ambient transaction and DTC), is to let NServiceBus do all the transaction handling. Therefore, you should either let your handler A) do its work, or B) throw an exception.
In both cases, the ambient transaction will ensure that any enlisted transactions will be committed/rolled back, depending on A or B.
I have a Workflow Service that has a few receives that listen to MSMQ queues. I would like to implement the following behavior:
If a correlation exception occurs (ie - workflow instance is gone), throw away the message.
If an InstanceLockException occurs (ie - this workflow instance is doing something on another server), put the message in the retry queue.
I have tried putting TransactedReceiveScope around the Receive activities, but it will put the message in the retry queue on a correlation error. Plus, it causes a lot of problems under heavy load.
Without the TransactedReceiveScope, the message is thrown away if there is an InstanceLockException.
Is there a way to implement this behavior (maybe via behavior extensions)?
You can implement a IErrorHandler for WCF to catch all unhandled exceptions whether thrown by your app or by WCF. The thing you have to be careful about with the netMsmqBinding is that throwing a fault in this handler means the message has been "successfully" processed and it will taken off the queue. In your case when InstanceLockException occurs, you'll have to let it remain unhandled if you want the built-in MSMQ 4 retry handling to occur. You'll also need to allow the PoisonMessageException to remain unhandled for proper MSMQ retrying to occur.
I'm not familiar with using Workflow, but knowing how MSMQ and WCF work you could try this
When a CorrelationException occurs:
Catch the exception
Return from your service method
Since your service method doesn't throw an exception it will think the message was successfully processed and remove it from the queue.
When a InstanceLockException occurs:
Catch the exception
rethrow the exception
Since your service method throws and exception it will think the message was not successfully processed and move it to the retry queue.
I think you'll have to create a WCF custom behavior to catch those exceptions.