what does retry in KafkaListenerContainerFactory really do? - spring-boot

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

Related

Spring #Retryable with configurable delay based on client

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.

Trying to redesign JMS configuration as Spring Integration: Redelivery policies

My legacy configuration exposes a ConnectionFactory #Bean of type ActiveMQConnectionFactory, with custom redelivery through activeMQConnectionFactory.setRedeliveryPolicy(..).
I found out that Spring Integration DSL allows redeliveries on the handle operation as well by means of RequestHandlerRetryAdvice, which can be configured for instance with an ExponentialBackOffPolicy.
I am wondering if they are triggering the same code at the lower level (not sure its a client thing or a signaling thing to the broker), and if not, whether they are equivalent and whether can I safely replace the abstract version without missing any configuratbility
No; it's completely different and has nothing to do with JMS and retrying incoming deliveries.
The retry advice is generally used to retry outgoing requests, e.g. an http request, or a send to JMS.

Usage of JMS to call a API which delivers a message

I would like to know if using a JMS in the below scenario is feasible or not.
I am adding a feature of calling an API service which will dispatch the emails to the customer.
So i thought of implementing a JMS in my application where i would put the events or messages in the queue and write a listener in the same application which will process the message and call the rest API service call which will dispatch the message to the customers.
My question was is it good to have a JMS in between the rest call and our application ?
Or should i directly call the rest api to dispatch the messages to the customer ?
I think that depends on the availability and overhead of your rest service.
If you know there will be times that your service will be down, but don't want to impact the process using the API, then JMS queues make since.
Or if you feel the rest service is causing a bottle neck from the API service side and want to queue up the messages somewhere where they can survive an outage of your own, JMS with a provider that supports persistent messages makes since in this case.
Using JMS would also open the door for completely decoupling the two. Whatever application hosts the rest service could just as easily be converted to pull messages from the JMS queue without a need to make a rest call if that seemed more efficient.
Just a few examples of how you could justify using JMS in this scenario.

Can I tell camel jms endpoint to share jms connections between routes?

I have a app server that runs multiple camel routes that are reading messages from a JMS Queue, each route runs with different selectors.
We have an app server for each group of clients. So at the end there are multiple connections created to the queue. And that seems to be affecting the read and write performance on the queue.
I tried to use a connection pool, (by the way i am using WMQ), the closest I got is to use spring's CachingConnectionFactory (as described in this post how to configure (spring) JMS connection Pool for WMQ).
I was hoping that the number of connections will reduce from each app server, but that did not happen. Even though i set the size to 5 on the CCFactory, i see 10 connections created to the queue. According to the documentation on CCFactory, explicit closing of the connections is required. Is it possible or does it even make sense to close the connection that is used by a camel route that is reading from a queue? Or is there a way to tell camel routes to share the connections? I thought the use of connection pool and factory will do that, but i don't see that from happening.
Can I achieve what I want to achieve?
Thanks in advance.
what you can do is have only one route reading from the queue instead of many, and then use some camel conditional logic to redirect the message to the correct processing route via direct endpoints, see also this example.
This way there would only one consumer for the queue, instead of multiple consumers each running it's own selector.

Spring Integration handle http outbound gateway failures

There are multiple servers that are listening to activemq. The chain is configured to make the http [outbound gateway] call. Suppose one of the server picks up the message and in-between if the http call fails for some reason. The message should be put back to the queue, so that another server can pick up the message and process. Can this be achieved using Spring Integration. I read lot on Transaction, however unable to find workable way.
Yes, simply set acknowledge="transacted" on the <int-jms:message-driven-channel-adapter/> and, as long as you use only direct channels (no <queue/> on the channel or task-executor on the channel's dispatcher) then any failure will cause the message to roll back.

Resources