当前位置: 首页 > 知识库问答 >
问题:

spring-retry-@circuitbreaker未重试

宗政浩慨
2023-03-14

我遇到了一个@circuitbreaker没有重试的问题。

我有一个服务类(例如类UserService和方法名getUser),这个方法调用另一个spring bean(例如AppClient和execute),后者又调用远程服务(REST调用)。execute方法用spring的@circuitbreaker-retry注释。

我在rest控制器中公开了对服务方法(类UserService和方法名getUser)的调用,并使用Postman对其进行了测试。下面是发生的情况--在超时错误的情况下,它确实调用了@recover方法。但它不会重试调用远程服务三次(默认值)。

如果我通过Postman手动运行它3次,断路器状态将变为打开,并将调用重定向到@recover方法,在重置超时后,它将恢复对远程服务的调用。

另外,我用@retryable替换了@circuitbreaker,这会调用三次(默认值)。我使用的是spring-重试版本1.2.1.release和aspectjtools版本1.6.2。

为什么不使用@circuitbreaker重试?我想有两个功能断路器和重试。根据文档,@Circuitbreaker应该同时执行这两项操作。如有任何帮助,我们将不胜感激。

@Configuration
@EnableRetry
public class cfgUserApp
{

}

@RestController
public class UserController
{
@Autowired
UserService userService;

@RequestMapping(value = "/user/{userId}", method = RequestMethod.GET, headers = "Accept=application/json")
public ResponseEntity<User> getUser(@PathVariable String userId) {
    return ok(userService.getUser(userId));
}
}

/* Spring Bean -- userService */

public class UserServiceImpl
implements userService
{

@Override
public User getUser( final String userId )
{
checkArgument( User != null && !User.isEmpty(), "User Id can not be null or empty." );
try
{
    final HttpGet request = buildGetUserRequest( userId );
    final User userResult = appClient.execute( request,
        response -> createGetReservationResult( response ) );
    return userResult;
}
catch ( final IOException e )
{
    LOG.error( "getUser failed.", e );
    throw new AppException(e.getMessage(), e);
}
}
}

public Class Appclient {

@Recover
public <T> T recover(AppException appException, final HttpUriRequest request,
                            final ResponseHandler<T> responseFunction )
{
    System.out.println("In Recovery");
    return <T>new User();
}

@CircuitBreaker( include = AppException.class, openTimeout = 5000l, resetTimeout = 10000l )
    public <T> T execute( final HttpUriRequest request,
                          final ResponseHandler<T> responseFunction )
                          {
                          // HTTP call
                          }
}

共有1个答案

左博学
2023-03-14

这可能是一个类似的问题--当使用JDK代理时找不到注释,因为您有接口

将批注移动到接口,或使用

@EnableRetry(proxyTargetClass = true)

我在PR中添加了另一个commit来解决这个问题。

编辑

您似乎误解了@circuitbreaker;它不会在内部重试;相反,它是一个有状态的重试拦截器,在超过断路器属性后进行故障转移。

我换了你的应用来做这个...

@GetMapping("/getnumber")
public int getNumber(){
    return this.userService.getNumber() + this.userService.getNumber() +
            this.userService.getNumber() + this.userService.getNumber();
}

然后我看到

getNumber
fallback
getNumber
fallback
getNumber
fallback
fallback

要实现(我认为)您想要的,您需要用一个重试服务包装服务,并将恢复放在那里:

@SpringBootApplication
@EnableRetry(proxyTargetClass = true)
public class DemoApplication {

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

@RestController
class UserRestController {

    private final RetryingUserService userService;

    @Autowired
    public UserRestController(RetryingUserService userService) {
        this.userService = userService;
    }

    @GetMapping("/getnumber")
    public int getNumber() {
        return this.userService.getNumber();
    }

}

@Service
class RetryingUserService {

    private final UserService userService;

    public RetryingUserService(UserService userService) {
        this.userService = userService;
    }

    @Retryable
    public int getNumber() {
        return this.userService.getNumber();
    }

    @Recover
    public int fallback(RuntimeException re) {
        System.out.println("fallback");
        return 2;
    }

}

@Service
class UserService {

    @CircuitBreaker(include = RuntimeException.class)
    public int getNumber() {
        System.out.println("getNumber");
        throw new RuntimeException();
    }

}

而且

getNumber
getNumber
getNumber
fallback

或者,您可能希望将重试放在断路器中,这取决于您希望的行为。

 类似资料:
  • Spring提供的声明式的重试类库。 示例代码: @Configuration@EnableRetrypublic class Application {    @Bean    public Service service() {        return new Service();    }}@Serviceclass Service {    @Retryable(RemoteAcces

  • 现在编译器很高兴了,所以我可以添加注释: 程序编译,运行,但是注释被完全忽略。

  • 当我运行单元测试时,我希望thisFails()方法重试3次,然后我希望看到recovery logger行打印出来,但它只尝试一次,然后抛出异常。底部的输出是在我运行测试之后。 我错过了什么? 请忽略此部分,然后跳到代码。门楣匠认为我没有足够的说明来张贴。我认为这样的措辞足以让我的问题被人理解,但出于某种原因,我不允许发布这个问题,除非我写更多的东西。还有更多的东西,等等。 --Spring启动

  • retry 如果源 Observable 产生一个错误事件,重新对它进行订阅,希望它不会再次产生错误 retry 操作符将不会将 error 事件,传递给观察者,然而,它会从新订阅源 Observable,给这个 Observable 一个重试的机会,让它有机会不产生 error 事件。retry 总是对观察者发出 next 事件,即便源序列产生了一个 error 事件,所以这样可能会产生重复的元

  • retry 函数签名: retry(number: number): Observable 如果发生错误,以指定次数重试 observable 序列。 示例 示例 1: 出错的话可以重试2次 ( StackBlitz | jsBin | jsFiddle ) // RxJS v6+ import { interval, of, throwError } from 'rxjs'; import {

  • 我试图测试使用自定义重试策略的重试模板。为了做到这一点,我使用以下示例: https://github.com/spring-projects/spring-retry/blob/master/src/test/java/org/springframework/retry/support/retrytemplatetests.java#l57 基本上,我的目标是在得到一些特定的http错误状态(例