Home > Blockchain >  Springboot @retryable listeners is invoked when retry is not triggered
Springboot @retryable listeners is invoked when retry is not triggered

Time:12-21

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:

  1. RetryListener doc

  2. full code is here

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.

  • Related