Spring #Retryable with configurable delay based on client - spring-boot

I am developing a Spring boot application. From my application we are calling an external RestService and want to retry if RestCall fails for any reason.
I know that #Retryable within spring should take care of this. I am trying to implement something like below with parameters:
#Retryable(maxAttempts=3,value=RunTimeException.class,backoff = #Backoff(delay = 900000))
Now my problem is, there are multiple clients who will call this service. When client1 is calling this service, i want to retry when a failure occurs after 15min. When client2 is calling this service, i want to retry when a failure occurs after 1sec.
So i want to know if there is any way we can configure the delay in retryable based on client1 or client2.
Any suggestions are helpful.

You can use a ThreadLocal<Long> #Bean to store the delay and then use delayExpression="#threadLocalBean.get().
However, suspending a thread for 15 minutes is a bit severe.
You would be better using a scheduler for the retries in that case.

Related

what does retry in KafkaListenerContainerFactory really do?

here is my confusion:
My Kafka Listener Container Factory has a retry template, where I have used the simple retry policy. My Consumer Kafka application basically, listens to a topic and make an API call to third party to send the events that it had listened to. While calling a third party api, I have used web client with RetryBackoffSpec as max attempts set to 3. So technically, my webclient call will make a 3 retry attempts while calling a third party api.
#Bean
public KafkaListenerContainerFactory kafkaListenerContainerFactory() {
ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory();
factory.setConsumerFactory();
factory.setErrorHandler();
factory.setRetryTemplate();
return factory;
}
In this case will it make sense for me to still have retry template in container factory?
What does retry(set in container factory) actually do, is it only making a retry to third party application in my case?
Since I am already calling third party api with web client with max attempts set to 3, in this situation will my total retries be 6? 3 from simple retry policy in container factory and 3 from webclient?
I also see some blogs saying simple retry policy which is set in container factory also keeps retrying to topics, what kind of use case we have it here?
So far I have simple retry policy (set to 3) and web client retry attempts set to 3. Wondering how it works internally.
It is fully depend what is your listener doing.
This retry on the container level is applied for the whole listener. If you don't not only an HTTP call, then you are not going to have one-to-one replacement for this retry instead of that reactive one.
If you have both, then it is not 6: every single attempt from the container is going to spawn all the attempts for Web Client until control comes back the container for the next attempt. So, together it is going to be 9.
The RetryTempalate support was deprecated in the recent versions. Consider to use respective DefaultErrorHandler or so: https://docs.spring.io/spring-kafka/docs/current/reference/html/#retrying-deliveries

Thread model for Async API implementation using Spring

I am working on the micro-service developed using Spring Boot . I have implemented following layers:
Controller layer: Invoked when user sends API request
Service layer: Processes the request. Either sends request to third-part service or sends request to database
Repository layer: Used to interact with the
database
.
Methods in all of above layers returns the CompletableFuture. I have following questions related to this setup:
Is it good practice to return Completable future from all methods across all layers?
Is it always recommended to use #Async annotation when using CompletableFuture? what happens when I use default fork-join pool to process the requests?
How can I configure the threads for above methods? Will it be a good idea to configure the thread pool per layer? what are other configurations I can consider here?
Which metrics I should focus while optimizing performance for this micro-service?
If the work your application is doing can be done on the request thread without too much latency, I would recommend it. You can always move to an async model if you find that your web server is running out of worker threads.
The #Async annotation is basically helping with scheduling. If you can, use it - it can keep the code free of the references to the thread pool on which the work will be scheduled. As for what thread actually does your async work, that's really up to you. If you can, use your own pool. That will make sure you can add instrumentation and expose configuration options that you may need once your service is running.
Technically you will have two pools in play. One that Spring will use to consume the result of your future, and another that you will use to do the async work. If I recall correctly, Spring Boot will configure its pool if you don't already have one, and will log a warning if you didn't explicitly configure one. As for your worker threads, start simple. Consider using Spring's ThreadPoolTaskExecutor.
Regarding which metrics to monitor, start first by choosing how you will monitor. Using something like Spring Sleuth coupled with Spring Actuator will give you a lot of information out of the box. There are a lot of services that can collect all the metrics actuator generates into time-based databases that you can then use to analyze performance and get some ideas on what to tweak.
One final recommendation is that Spring's Web Flux is designed from the start to be async. It has a learning curve for sure since reactive code is very different from the usual MVC stuff. However, that framework is also thinking about all the questions you are asking so it might be better suited for your application, specially if you want to make everything async by default.

How to make Spring Boot REST controller asynchronous?

My application is simple 3-tier Spring Boot rest web-service with usual synchronous endpoints.
But since the period of getting response from downstream system where my service sends requests is quite long (kind of 60 seconds), I need to add support of asynchronous REST calls to my service to save upstream systems from a response awaiting. In other words, if a response to a downstream system is going to take more than 60 seconds (timeout), then the upstream system break the connection with my service and keeps its doing...
But when the response come, my service using "reply-to" header from the upstream system will send the response to the upstream system.
All the things above are kind of call back or webhook.
But I didn't find any examples of implementation.
How to implement this mechanism?
How can I find more information?
Does Spring Boot have something to implement it out-of-box?
Thank you for attention!
You can use the #Async annotation from Spring. You will also need to enable in your application this by setting #EnableAsync.
An important note is that your method with the #Async annotation should be on a different class from where it is being called. This will let the Spring proxy intercept the call and effectively do it asynchronous.
Please find here the official tutorial.

Is there a good practice to have cron jobs in a spring webflux app?

For a while now, our team started to work on a reactive new micro-service. The service is mainly using spring-webFlux and other cool reactive futures.
At this point there should be created a cron-job triggered every 10 secs(that has to verify some transactions state), but I'm afraid that this will affect the load of the app and also is not compatible with the reactive concurrency model since the #Scheduled job when will be triggered it's going to consume one thread until it ends.
At this point I'm more in favor of an aws-lambda that it's going to call an endpoint of our app.
Do you have any better suggestions or advices ?
You can't schedule an AWS Lambda to run more often than once a minute. If you need an event to occur every 10 seconds in Spring I think using #Scheduled is your best option.

Does Spring make "calling its own controller" multithread?

I have an spring boot application that pulls message from an cloud message queue and put it back to a cloud db. I realize that my program is single thread(I am not using request mapping, just pull,process,put to db). I want Spring handle concurrency things. So can I make a dispatcher function, which calls controller in the application with #RequestMapping?
#RestController
#RequestMapping("/test")
public class GatewayController {
#RequestMapping("/service")
public void InvokeService(...) {...}
}
I need mutithread to call other service for response, which I don't want it to block others. If I recieve 10 messages, I want it to call /test/service... which have 10 threads processing them.
My question is:
Will Spring make the controller multithread?
How to call its own controller? Send request to the url? (I don't need response from controller, just let controller call a service to put response in a db on could)
RequestMapping is MVC thing - intended to issue http requests. And yes, it uses tomcat under the hood.
If you'll inject RestController into your class it won't issue any HTTP requests, you'll only call the controller as a regular bean. If you consume messages in one thread, it won't become multithreaded to answer your first question.
You can, of course, create HTTP request but frankly it's just wrong. So don't do it. This answers your second question to some extent :)
Now, there is nothing wrong conceptually if your microservice acts as a consumer and producer and deals with queues, not all microservices have to be accessible via HTTP.
In order to work in a multi threaded environment:
Check whether you can consume messages in a multi-threaded manner. Maybe the client of your "cloud message queue" offers multi-threaded configuration (thread pool or something).
If it's not possible, create a thread pool executor by yourself and upon each message submit the processing task to this thread pool. This will make the processing logic multithreaded with a parallelism level confined by the thread pool size and thread pool configurations.

Resources