【问题标题】:Resilience4j + Spring boot @Retry not working with async methodsResilience4j + Spring boot @Retry 不能使用异步方法
【发布时间】:2021-04-27 11:09:35
【问题描述】:

我有一个@Async 方法,我试图在其中添加@Retry,但是当发生异常时永远不会执行回退方法。我也在尝试测试这种抛出异常的模拟,但由于它永远不会进入回退方法,所以它永远不会成功。

这是我的代码:

@Retry(name = "insertarOperacionPendienteService", fallbackMethod = "fallbackInsertarOperacionPendiente")
@Override
@Async
public CompletableFuture<String> insertarOperacionPendiente(final OperacionPendienteWeb operacionPendienteWeb)  throws InterruptedException, ExecutionException {
    StringBuilder debugMessage = new StringBuilder("[insertarOperacionPendiente] Operacion pendiente a insertar en BB.DD.: ").append(operacionPendienteWeb);
    CompletableFuture<String> result = new CompletableFuture<>();
    HttpEntity<List<OperacionPendienteWeb>> entity = new HttpEntity<>();
    UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("url");
    try {
        rest.exchange(builder.toUriString(), HttpMethod.POST, entity, Void.class);
    } catch (HttpClientErrorException | HttpServerErrorException e) {
        result.completeExceptionally(e);
    } catch (Exception e) {
        result.completeExceptionally(e);
    }   

    result.complete("OK");
    return result;
}

public CompletableFuture<String> fallbackInsertarOperacionPendiente(Exception e) {
       System.out.println("HI");
       throw new InternalServerErrorDarwinException("Error al insertar la operacion pendiente.");
}

测试:

@Test(expected = InternalServerErrorDarwinException.class)
public void procesarOperacionPendienteKO1() throws InterruptedException, ExecutionException, ParseException {
    when(rest.exchange(Mockito.anyString(), 
            Mockito.any(HttpMethod.class), 
            Mockito.any(HttpEntity.class), 
            Mockito.eq(Void.class)))
    .thenThrow(new NullPointerException());

    this.operacionesPendientesService.insertarOperacionPendiente(obtenerOperacionPendienteWeb()).get(); 

    verify(rest, timeout(100).times(1)).exchange(Mockito.anyString(), 
            Mockito.any(HttpMethod.class), 
            Mockito.any(HttpEntity.class), 
            Mockito.eq(Void.class));

}

我错过了什么吗?

谢谢!

【问题讨论】:

  • 我首先注意到的一件事是您捕获了所有异常。所以不会有重试恕我直言
  • result.completeExceptionally(e);就像一个“扔”。如果我改用“throw”,它也不起作用,如果我把方法重新同步,它就起作用了

标签: spring-boot junit mockito resilience4j resilience4j-retry


【解决方案1】:

您的代码如下所示:

try {
    rest.exchange(builder.toUriString(), HttpMethod.POST, entity, Void.class);
} catch (HttpClientErrorException | HttpServerErrorException e) {
    result.completeExceptionally(e);
} catch (Exception e) {
    result.completeExceptionally(e);
}   

result.complete("OK");

所以在最后一行你总是将结果设置为完成!

改成:

try {
    rest.exchange(builder.toUriString(), HttpMethod.POST, entity, Void.class);
    result.complete("OK");
} catch (HttpClientErrorException | HttpServerErrorException e) {
    result.completeExceptionally(e);
} catch (Exception e) {
    result.completeExceptionally(e);
}   

【讨论】:

  • 它现在正在执行此更改的回退,但它返回的是 ExecutionException 而不是 InternalServerErrorDarwinException。为什么?
  • 您的异常是否嵌套在 ExecutionException 中?
  • 不知道你说的“嵌套”是什么意思
  • 如果你调用getCause()的异常是你的异常的原因吗?
  • 你确定 fallbackInsertarOperacionPendiente 被调用了吗?
猜你喜欢
  • 2020-09-19
  • 2020-09-10
  • 2020-09-15
  • 2021-01-19
  • 1970-01-01
  • 2022-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多