Error Handling in single threaded applications - spring-integration

In a single threaded Spring Integration, application where the entire pipleine is running within the same transaction, an error channel is not applicable. Instead, exceptions will be thrown back to the caller.
The way I am doing this is to define a service activator which is the first of a chain of components which handle an incoming message.
#ServiceActivator
public Message handleException(Message message) {
try {
return message;
}
catch (Throwable throwable){
// HANDLE ERROR
}
return null;
}
Is this the correct approach, or is there a better strategy?
Thanks

No; that won't do anything at all; it will simply pass the message to the next element in the chain. If you don't need to handle the error in any way, and just want it thrown back to the caller, you need to do nothing. If the start of the flow is a gateway, the gateway will unwrap the cause from the MessagingException.
You can, of course, put an error-channel on the gateway and handle it there.
It's generally best to provide some more details about your flow (entry point etc), when asking these general questions.

Related

Proper way to handle 412 Precondition failure from cosmosdb in an event driven system with application implemented in nodejs

I have an event-driven system with my application implemented in nodejs using cosmosdb (azure-cosmosdb-sqlapi) to store the events. I have planning data coming via various events from kafka broker, to complete a planning documnet I need to combine data from 5 different events, I combine the events using planning id. In such a system for upsert operation we encounter 412 Precondition failure error very often, as we receive many events for a planning id.
The official Microsoft link says to retry. I am confused about which approach to take to retry
Handle the error code using a try catch and call the method handling the event from catch block for n number of times. If the retry fails after n times throw the exception back to broker, in that case the event is send again by the broker. The issue with this is I am not able to add test for the same. Secondly I need to manage all the retry logic in my code base. The advantage here is that I know that an event is failed and I can retry directly without sending the event back to broker. Below is the the snippet from planningservice.ts handlePlanningEvents method
try {
await repository.upsert(planningEntry, etag)
} catch (e: any) {
if (e.code === 412 and retries) {
this.handlePlanningEvents(event, retries-1)
} else {
throw e // throws exception back to broker
}
}
Not using try catch to handle the error in service code but propagating the error to controller where it sends a 500 error response to broker and the broker sends the event again. The issue with this case is that it's longer path as compared to using try catch where I can retry directly. But the advantage here is that I don't to worry about retry logic anymore its handled by broker, less and cleaner code.
Not sure which approach to take, also open to other suggestions.

Spring-Integration AbstractRequestHandlerAdvice with webflux/reactive: does this introduce a synchronous process?

I've implemented an advice handler attached to outbound-gateway components in order to be able to long outgoing HTTP requests before/after. Originally, this was for a Spring-Integration project using MVC/servlet underpinnings. (Original question: Logging http request in Spring integration http outbound gateway )
We are attempting a migration to webflux/reactive which means that we are using a webflux:outbound-gateway in lieu of a http:outbound-gateway.
The advice handler is an around call in the doInvoke() method:
public class MyLogger extends AbstractRequestHandlerAdvice {
// ...
#Override
protected Object doInvoke(ExecutionCallback callback, Object target, Message<?> message(
{
// ... logging before the call ...
Object result = callback.execute();
// ... logging after the call ...
return result;
}
}
Whereas I understand that the webflux:outbound-gateway call itself is supposed to be asynchronous (i.e. no threads waiting on a response), it would seem to me that the advice handler itself must be implemented synchronously (i.e. thread awaiting the response). Am I understanding correctly? Is the advice handler adding synchronicity that wouldn't otherwise be there?
Thanks for any insights on this point.
There is a ReactiveRequestHandlerAdvice for this particular use-case to wrap a reply Mono with anything you'd like: https://docs.spring.io/spring-integration/docs/current/reference/html/messaging-endpoints.html#reactive-advice

Handling Error in asynchronous process using #Async annotation on custom method vs on #Gateways method

I have a process where I need to upload file to Sftp server asynchronously. So after exploring more about Async in gateways I found that I need to have error channel defined in #MessagingGateway parameter then handler to handle the Exception propagated to error channel but I felt handling this way is complicated for me, as I will have to update Pojo field and persist into DB depending on the file upload, success or failure.
So I thought of having a custom method annotated with #Async and call the gateway method. Also surround gateway method with try block and catch any exception occurred in the downstream
Code Sample:
#Async
void upload(Resource file, FileStatus fileStatus){
try{
uploadGateway.upload(file,fileStatus.getFilePath(),fileStatus.getFileName());
}catch(RuntimeException e){
fileStatus.setUploadStatus("Failed");
//save into db
}
}
Upload Gateway without error channel so that error can be sent back to caller
#MessagingGateway
public interface UploadGateway {
#Gateway(requestChannel = "input.channel")
void upload(#Payload Resource file, #Header("path") String path, #Header("name") String fileName);
}
Handler:
#Bean
public IntegrationFlow uploadDocument() {
return IntegrationFlows.from("input.channel")
.log(LoggingHandler.Level.WARN)
.handle(Sftp.outboundAdapter(sftpSessionFactory(), FileExistsMode.FAIL)
.autoCreateDirectory(true)
.remoteDirectoryExpression("headers['path']")
.fileNameExpression("headers['name']"))
.get();
}
Question:
What will be the consequences if I'm handling error this way? Is this the right way to handle any error occurred in downstream flow?
Since #MessagingGateway is like an RPC in messaging, it is fully OK to catch an exception on its method call like that. Since you make your flow fully sync, it works like typical Java exceptions sub-system.
Your concern about async error handling with errorChannel really makes sense since it is similar in complexity with standard Java async method handling and its errors processing.
On the other hand it is really commended to handle errors downstream via errorChannel if that is going to be some complex logic in some other flow. Plus you are going to return back some compensation message.
However in the end of day the choice is yours: there is no drawbacks to handle errors yourself.
See Error Handling chapter for more food to think on.

Azure IoTHub throwing exceptions I cannot catch

I have a Xamarin app using the Microsoft.Azure.Devices.Client.DeviceClient to listen for messages from the Azure IoT hub. Occasionally I get errors thrown that I cannot catch, and deal with. One such exception is:
Microsoft.Azure.Devices.Client.Exceptions.UnauthorizedException
This exception is just an example of an exception I am getting, and one that I can reliably recreate by changing system time. Other IoTHubExceptions are sporadic and difficult to recreate and hence the need to try and catch the exception.
Can anyone tell me how I can catch these IoT hub based errors? The code is:
try
{
await _deviceClientInbound.OpenAsync();
// execution never gets passed this line and the exception is eventually thrown, having reached this point
Message receivedMessage = await _deviceClientInbound.ReceiveAsync();
if (receivedMessage == null) continue;
await _deviceClientInbound.CompleteAsync(receivedMessage);
}
catch (Exception e)
{
// Exception is never caught in here ...
// How can I catch the IoTHubException based exceptions
}
If you are getting unauthorized exception . Then please check your iot hub connection string used in device client to confirm that the shared access polity used with connection string have all the privileges or not, that is needed at your end.
I believe this has to do with the various refactorings done for the supported platforms and you will likely have to catch all exceptions, process the ones you want, and rethrow ones you don't. Depending on platform you might be able to include:
using Microsoft.Azure.Devices.Client.Exceptions;
The sources are here if you feel like spelunking:
https://github.com/Azure/azure-iot-sdk-csharp/search?utf8=%E2%9C%93&q=using+Microsoft.Azure.Devices.Client.Exceptions

Unable to throw CustomException from fault-Message Resolver

I am calling 2 different web services using two webservice outbound gateways in my Spring integration gateway flow.
I have implemented 2 fault Resolver , in each gateway to resolve SOAP faults
and want to create custom application exception and throw from resolver to my exception handler.
My FaultResolver is getting called whenever we receieve the SOAP fault from service call.
But I am not been able to throw custom excetion from my resolver as its only allowing me to throw IOException.
Due to this I am throwing a Runtime Exception with message from my resolver and catching this Runtime Exception in my Exception Handler.
Is it correct practice to throw a runtime exception and catching in Handler or is ther any other better way to handle this scenario or any other implementation to handle SOAP Fault and throw custom Exception.
The best way to determine if your solution is good or not, just try to find some out-of-the-box implementation on the matter. One of them is:
public class SimpleFaultMessageResolver implements FaultMessageResolver {
public void resolveFault(WebServiceMessage message) {
if (message instanceof FaultAwareWebServiceMessage) {
throw new WebServiceFaultException((FaultAwareWebServiceMessage) message);
}
else {
throw new WebServiceFaultException("Message has unknown fault: " + message);
}
}
}
where WebServiceFaultException is exactly RuntimeException.
So, I think you are fine to go ahead.

Resources