I am using @Retryable like following where I am retrying a db save function in a service class. I want to tract the retrying. But the retry functions are always invoked in the listener.
PeopleService.java
package com.test.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.beans.factory.annotation.Autowired;
@Service
public class PeopleService {
@Autowired
private PeopleRepository peopleRepository;
@Retryable(value = {Exception.class}, maxAttempts = 3,
backoff = @Backoff(delay = 200), listeners = {"retryListener"})
public void addPeople() throws Exception{
People p = new People(20, "James", "bond");
peopleRepository.save(p);
}
}
I have a listener like this which was passed to listener in @Retryable.
RetryListener.java
package com.test.demo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.listener.RetryListenerSupport;
import org.springframework.stereotype.Component;
@Slf4j
@Component
class RetryListener extends RetryListenerSupport {
@Override
public <T, E extends Throwable> void close(RetryContext context,
RetryCallback<T, E> callback, Throwable throwable) {
System.out.println("Unable to recover from Exception");
System.out.println("Error ");
super.close(context, callback, throwable);
}
@Override
public <T, E extends Throwable> void one rror(RetryContext context,
RetryCallback<T, E> callback, Throwable throwable) {
System.out.println("Exception Occurred, Retry Count " context.getRetryCount());
super.onError(context, callback, throwable);
}
@Override
public <T, E extends Throwable> boolean open(RetryContext context,
RetryCallback<T, E> callback) {
System.out.println("Exception Occurred, Retry Session Started ");
return super.open(context, callback);
}
}
Now I am calling the service class method from another component class.
Demo.java
package com.test.demo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.beans.factory.annotation.Autowired;
@Slf4j
@Component
public class Demo {
@Autowired
private PeopleService peopleService;
@Scheduled(initialDelay = 5000L, fixedDelay = 1000L)
private void perMinuteStatsTask() {
try {
System.out.println("adding people");
peopleService.addPeople();
}catch(Exception ex)
{
ex.printStackTrace();
}
}
}
Now the thing is, the one rror(), close(), open() is being called even if there is no retry. I am seeing something like this as output for retry case and also for non-retry case.
adding people
Exception Occurred, Retry Session Started
Hibernate:
insert
into
people
(age, first_name, last_name)
values
(?, ?, ?)
Unable to recover from Exception
Error
some links:
CodePudding user response:
open()
and close()
are always called.
This is simply wrong:
@Override
public <T, E extends Throwable> boolean open(RetryContext context,
RetryCallback<T, E> callback) {
System.out.println("Exception Occurred, Retry Session Started ");
return super.open(context, callback);
}
/**
* Called before the first attempt in a retry. For instance, implementers can set up
* state that is needed by the policies in the {@link RetryOperations}. The whole
* retry can be vetoed by returning false from this method, in which case a
* {@link TerminatedRetryException} will be thrown.
* @param <T> the type of object returned by the callback
* @param <E> the type of exception it declares may be thrown
* @param context the current {@link RetryContext}.
* @param callback the current {@link RetryCallback}.
* @return true if the retry should proceed.
*/
Similarly for close.
System.out.println("Unable to recover from Exception");
That's not what close()
means.