Throwing exception from ServiceActivator vs. Filter behaves differently - spring

In our application we have error handling mechanism, where we throw runtime exceptions on an error. I noticed a strange behavior and I want to understand the mechanism underlying this one
1) Situation 1: Exception thrown from ServiceActivator is converted to MessageHandlingException
When an error occurs in a ServiceActivator, we throw an exception. The message we get on ErrorChannel has PayLoad as org.springframework.integration.MessageHandlingException and actual exception thrown as cause
2) Situation 2: Exception thrown from Filter is not masked with MessageHandlingException
When an error occurs in Filter, and we throw exception, then PayLoad is actual exception, and is not masked with org.springframework.integration.MessageHandlingException
I have a few questions:
Why exception throwing from ServiceActivator behaves differently than in Filter
Are there some "best practices" around error handling in Spring-integration projects, while utilizing the errorChannel and related infrastructure
Update 1:
Filter extends AbstractFileListFilter which is part of a filter chain- a custom CompositeFileFilter which implements FileListFilter
CompositeFileFilter is being used by a file:inbound-channel-adapter and which passes the output to a Channel declared below:
<int:channel
id="channelForFilesComingIn"
datatype="java.io.File"
>
<int:dispatcher task-executor="dispatchExecutor" />
</int:channel>
Update 2:
Whet we are trying to do is read files from filesystem and process them. In file reading part, using file:inbound-channel-adapter with a CompositeFilter which filters files which are not completely uploaded or don't meet naming standards.
After all filters pass, file is handed over to a ServiceActivator for processing
In any of above (Filter chain or Service) , if there is an error condition, it has to be reported to DB and by email. For achieving this we are throwing ApplicationException which are caught by errorChannel, and passed to specialized channels.

Just to make it clear, a MessageHandlingException is thrown (wraps user exception) when a Message HANDLER fails - a message handler is something that HANDLES a message.
If an exception is thrown in the MessageSource, there is no message yet so a MessageHandlingException (or any MessagingException) does not apply.
Instead, the poll fails and the exception is thrown back to the poller.
If you want to handle exceptions in a polled endpoint (MessageSource), you need to give the poller an ErrorHandlingTaskExecutor, to which you can provide an ErrorHandler and do what you want with the exception, but since there is no message yet, it is the original exception thrown by the MessageSource.
If you want to send it to the error channel, you'll need to do that in your custom ErrorHandler.

Related

How to cancel the consumer method in MassTransit

How can I cancel the execution of a Consume method of an IConsumer<>? I tried to create a cancellation token and use another thread to trigger the cancellation, and I can get a ConsumerCancelledException, but I could not handle the Fault<> message. E.g.
I have a MyDataConsumer: IConsumer<MyData> and MyDataFaultConsumer: IConsumer<Fault<MyData>>: IConsumer<Fault<MyData>>
The IConsumer<MyData> throws an ConsumerCancelledException
The failed message went into the MyData_error queue, but it did not go to the MyDataFault queue
However, if I directly throw an exception in my MyDataConsumer, my fault consumer can get the data. It seems the ConsumerCancelledException is handled differently than other exceptions.

What is the use of loop.call_exception_handler(context)

Kindly help to provide one sample usage of loop.call_exception_handler(context) with an example in asyncio. When loop.get_exception_handler() is already present, why do someone need to call the exception handler explicitly. Also if loop.get_exception_handler() is not set, then what do loop.call_exception_handler(context) call.
call_exception_handler is a convenience function that encapsulates the logic of invoking the custom exception handler or the default exception handler, and of falling back to the default exception handler if the custom one itself fails. It is designed to be called from code that encounters an exception but doesn't have a "caller" to propagate it to. For example:
The handle that implements call_soon and call_later catches exceptions while invoking the provided function and uses call_exception_handler to report it.
The server part of the event loop code that calls accept in a loop uses call_exception_handler to report exceptions raised by accept. It cannot propagate the exception to its caller because it is running in a background task, so it has no caller.
Various parts of transports use call_exception_handler to report errors.
When loop.get_exception_handler() is already present, why do someone need to call the exception handler explicitly.
Because get_exception_handler() only invokes the custom exception handler, if one is set. If one is not set, the default exception handler is returned. And if one is set, and it raises an exception, the default exception handler is used to report that exception. And errors like SystemExit and KeyboardInterrupt are carefully ignored. It would be tedious and error-prone to repeat this logic in every place that needs to invoke the exception handler, so call_exception_handler was created.

MassTransit fault consumer not invoked for request/response

What is the best practice for handling exceptions in MassTransit 3+ with regard to Request/Response pattern? The docs here mention that if a ResponseAddress exists on a message, the Fault message will be sent to that address, but how does one consumer/receive the messages at that address? The ResponseAddress for Bus.Request seems to be an auto-generated MassTransit address that I don't have control over, so I don't know how to access the exception thrown in the main consumer. What am I missing? Here's my code to register the consumer and its fault consumer using Unity container:
cfg.ReceiveEndpoint(host, "request_response_queue", e =>
{
e.Consumer<IConsumer<IRequestResponse>>(container);
e.Consumer(() => container.Resolve<IMessageFaultConsumer<IRequestResponse>>() as IConsumer<Fault<IRequestResponse>>);
});
And here's my attempt at a global message fault consumer:
public interface IMessageFaultConsumer<TMessage>
{
}
public class MessageFaultConsumer<TMessage> : IConsumer<Fault<TMessage>>, IMessageFaultConsumer<TMessage>
{
public Task Consume(ConsumeContext<Fault<TMessage>> context)
{
Console.WriteLine("MessageFaultConsumer");
return Task.FromResult(0);
}
}
This approach DOES work when I use Bus.Publish as opposed to Bus.Request. I also looked into creating an IConsumeObserver and putting my global exception logging code into the ConsumeFault method, but that has the downside of being invoked every exception prior to the re-tries giving up. What is the proper way to handle exceptions for request/response?
First of all, the request/response support in MassTransit is meant to be used with the .Request() method, or the request client (MessageRequestClient or PublishRequestClient). With these methods, if the consumer of the request message throws an exception, that exception is packaged into the Fault<T>, which is sent to the ResponseAddress. Since the .Request() method, and the request client are both asynchronous, using await will throw an exception with the exception data from the fault included. That's how it is designed, await the request and it will either complete, timeout, or fault (throw an exception upon await).
If you are trying to put in some global "exception handler" code for logging purposes, you really should log those at the service boundary, and an observer is the best way to handle it. This way, you can just implement the ConsumeFault method, and log to your event sink. However, this is synchronous within the consumer pipeline, so recognize the delay that could be introduced.
The other option is to of course just consume Fault<T>, but as you mentioned, it does not get published when the request client is used with the response address in the header. In this case, perhaps your requester should publish an event indicating that operation X faulted, and you can log that -- at the business context level versus the service level.
There are many options here, it's just choosing the one that fits your use case best.

Spring Integrations Flow: Error Handling Design

Looking for advice on error handling using spring IntegrationFlows. I have a set up with many flows with a mixture of routing, transformations and channels this is fully working.
Currently for error handling I catch all checked expectations that a given .handle(..) may throw and re-throw them as a Runtime exception. This causes the exception to hit my error channel, where I deal with the problem. I am looking to see if this is how the use of channels and Integrations flows was designed.
return IntegrationFlows.from("test")
.handle(X.class, (p, h) -> process(p))
.handle(More::EndPorcess)
.get();
Sorry, what is the question though?
It isn't regular Java, so there is something in between operators. It is message channel. And that is really designed to end up in the errorChannel if there is no ability to bubble exception as a StackTrace: http://docs.spring.io/spring-integration/docs/4.3.5.RELEASE/reference/html/configuration.html#namespace-errorhandler

Spring Integration error channel solution

Hello I'm very very new to Spring Integration.
I have known that error channel throws exception parameter to the channel.
but when program are working in error handling I need to get the current state before exception occur(eg. an object that setting some value in main process or string)
the question is how can I sent other parameter(eg. an object) come with exception to error channel?
or I have to use other solution?
thank you,
well, you get something like (Message < MessageHandlingException > msg ) as parameter in error handler method. Then using
msg.getPayload().getFailedMessage()
you gain access to message which failed. If its not enough then you can set your object as header with < header-enricher > somewhere before possible exception and fetch it in you error handler:
msg.getPayload().getFailedMessage().getHeaders().get("trackedImage");

Resources