Springboot @retryable не повторяет попытку

Следующий код не повторяется. Что мне не хватает?

@EnableRetry
@SpringBootApplication
public class App implements CommandLineRunner
{
    .........
    .........


    @Retryable()
    ResponseEntity<String> authenticate(RestTemplate restTemplate, HttpEntity<MultiValueMap<String, String>> entity) throws Exception
    {
        System.out.println("try!");
        throw new Exception();
        //return restTemplate.exchange(auth_endpoint, HttpMethod.POST, entity, String.class);
    }

Я добавил следующее в pom.xml.

    <dependency>
        <groupId>org.springframework.retry</groupId>
        <artifactId>spring-retry</artifactId>
        <version>1.1.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>

Я также пытался предоставить различные комбинации аргументов @Retryable.

@Retryable(maxAttempts=10,value=Exception.class,backoff=@Backoff(delay = 2000,multiplier=2))

Спасибо.


person engg    schedule 05.07.2016    source источник
comment
Я столкнулся с той же проблемой.   -  person Ferdous Wahid    schedule 17.12.2016


Ответы (8)


В выпуске spring boot 2.0.2 я заметил, что @Retryable не работает, если у вас есть повторяемый и вызываемый метод в том же классе. При отладке обнаружено, что pointcut не строится должным образом. На данный момент обходной путь для этой проблемы заключается в том, что нам нужно написать метод в другом классе и вызвать его.

Рабочий пример можно найти здесь.

person nkharche    schedule 27.06.2018
comment
У меня был такой же опыт с весенней загрузкой 1.5.x. - person Cornelia Davis; 03.07.2018
comment
наблюдал то же самое с весенней загрузкой 2.0.0 до 2.0.5. Проверено репозиторий mvn: нет версии spring-retry после 2017 года, в то время как spring boot 2 появился в 2018 году. Есть ли спаситель, которому удалось заставить spring-retry работать с любой версией spring-boot 2.x? Тем временем откатился на весеннюю загрузку 1.5.15, и он отлично работает. - person Jeremie; 06.09.2018
comment
это обычная пружинная штука, вы можете использовать самоссылку @Autowired? - person Kalpesh Soni; 27.08.2019
comment
Именно так работают все аннотации Spring. Вам нужен отдельный прокси-объект, чтобы Соринг мог применять дополнительную логику. - person iozee; 30.03.2020
comment
Это связано с тем, что Spring создает прокси-объект для обработки повторных попыток и не может создать прокси-объект сам по себе. Та же проблема возникает при использовании других аннотаций, таких как @Transactional - person Federico Piazza; 30.04.2020

Чтобы аннотация @Retryable в методе была обнаружена, она должна быть правильно вызвана из инициализированного контекста. Вызывается ли метод из bean-компонента из контекста Spring или вызывается другими способами?

Если вы тестируете это, ваш бегун использует SpringJunit4ClassRunner?

person UserF40    schedule 08.07.2016
comment
Спасибо, у меня нет возможности посмотреть на это, я вернусь. - person engg; 17.07.2016
comment
Это должен быть принятый ответ, когда вы говорите, что я понял, что если вернуть что-то из метода, который вы пытаетесь повторить, то @Retryable() не работает. неверно, вы действительно можете вернуть объект в методе повторной попытки, дело в том, что метод нужно вызывать из компонента. - person fsimon; 20.08.2017

Я решил это. Я понял, что если что-то вернуть из метода, который вы пытаетесь повторить, то @Retryable() не работает.

зависимость maven в pom.xml

    <dependency>
        <groupId>org.springframework.retry</groupId>
        <artifactId>spring-retry</artifactId>
        <version>1.1.5.RELEASE</version>
    </dependency>

Весенняя загрузка Application.java

@SpringBootApplication
@EnableTransactionManagement
@EnableRetry
public class Application {

     public static void main(String[] args) throws Exception {
       SpringApplication.run(Application.class, args);
     }

}

в контроллере.java

@RestController
public class JavaAllDataTypeController {

@Autowired
JavaAllDataTypeService JavaAllDataTypeService;


@RequestMapping(
        value = "/springReTryTest",
        method = RequestMethod.GET
)
public ResponseEntity<String> springReTryTest() {

    System.out.println("springReTryTest controller");

    try {
         JavaAllDataTypeService.springReTryTest();
    } catch (Exception e) {
        e.printStackTrace();
    }

    return new  ResponseEntity<String>("abcd", HttpStatus.OK);
  }

}

в сервисе.java

@Service
@Transactional
public class JavaAllDataTypeService {

 // try the method 9 times with 2 seconds delay.
 @Retryable(maxAttempts=9,value=Exception.class,backoff=@Backoff(delay = 2000))
 public void springReTryTest() throws Exception {

    System.out.println("try!");
    throw new Exception();
  }

}

вывод: он пытается 9 раз, а затем выдает исключение.

введите здесь описание изображения

person Ferdous Wahid    schedule 18.12.2016

Он также работает для возвращаемого типа

@Service
public class RetryService {

private int count = 0;

// try the method 9 times with 2 seconds delay.
@Retryable(maxAttempts = 9, value = Exception.class, backoff = @Backoff(delay = 2000))
public String springReTryTest() throws Exception {
    count++;
    System.out.println("try!");

    if (count < 4)
        throw new Exception();
    else
        return "bla";
  }

}
person Chinmay Samant    schedule 12.03.2018

У меня была точно такая же проблема, как описано в исходном вопросе.

В моем случае оказалось, что случайно не была включена зависимость spring-boot-starter-aop. После добавления его в мой pom.xml мои методы @Retryable работали, как и ожидалось.

Возврат значений из методов @Retryable у меня отлично работает.

person Bas Cancrinus    schedule 13.05.2019

Альтернативой может быть RetryTemplate

@Bean
    public RetryTemplate retryTemplate() {
        RetryTemplate retryTemplate = new RetryTemplate();

        FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
        fixedBackOffPolicy.setBackOffPeriod(2000l);
        retryTemplate.setBackOffPolicy(fixedBackOffPolicy);

        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
        retryPolicy.setMaxAttempts(2);
        retryTemplate.setRetryPolicy(retryPolicy);

        return retryTemplate;
    }

а также

retryTemplate.execute(new RetryCallback<Void, RuntimeException>() {
    @Override
    public Void doWithRetry(RetryContext arg0) {
        myService.templateRetryService();
        ...
    }
});

сработало для меня

источник

person BiScOtTiNo    schedule 21.02.2019

Даже я столкнулся с той же проблемой. Позже, после некоторого расследования и исследований, я узнал, что наряду с аннотацией @Retryable над методом нам также необходимо предоставить @EnableRetry над классом. Эта аннотация @EnableRetry может быть предоставлена ​​либо над тем же классом, в котором вы предоставили метод, который вы хотите повторить, либо над вашим основным классом весеннего загрузочного приложения. Например вот так:

@RequiredArgsConstructor
**@EnableRetry**
@Service
public class SomeService {

  **@Retryable(value = { HttpServerErrorException.class, BadRequestException.class},
      maxAttempts = maxRetry, backoff = @Backoff(random = true, delay = 1000,
                         maxDelay = 8000, multiplier = 2))**
  public <T> T get( ) throws  HttpServerErrorException, BadRequestException {
    
     //write code here which you want to retry
  }

}

Я надеюсь, что это поможет и решить вашу проблему.

person Mahesh Daksha    schedule 20.02.2021

Для тех, кто хочет вызвать блок @Retryable в классе Come, можно сделать это.

Ключевым моментом здесь является не вызов метода напрямую, а через самоинжектируемый bean-компонент.

@Slf4j
@Service
public class RetryService {

    @Resource(name = "retryService")
    private RetryService self;

    public String getValue(String appender) {
        return self.getData(appender);
    }

    @Retryable(value = NumberFormatException.class, maxAttempts = 4, backoff = @Backoff(500))
    public String getData(String appender) {
        log.info("Calling getData");
        Integer value = Integer.parseInt(appender);
        value++;
        return value.toString();
    }

    @Recover
    public String recoverData(String appender) {
        log.info("Calling recoverData");
        return "DEFAULT";
    }

}

Подробно об использовании Retry можно прочитать здесь

person MyTwoCents    schedule 07.05.2021