Spring-retry - @Circuitbreaker 没有重试
Spring-retry - @Circuitbreaker is not retrying
我运行遇到@CircuitBreaker 没有重试的问题。
我有一个服务 class(例如 Class UserService 和方法名称 getUser),此方法调用另一个 Spring bean(例如 AppClient 和 execute),这反过来使调用远程服务(REST 调用)。 execute 方法用 Spring-Retry.
的 @CircuitBreaker 注释
我已经在 rest 控制器中公开了对服务方法的调用(Class UserService 和方法名称 getUser),我使用 Postman 对其进行了测试。这是发生了什么——如果出现超时错误,它会调用@Recover 方法。但它不会重试三次调用远程服务(默认值)。
如果我通过 Postman 手动 运行 它 3 次,断路器状态变为 OPEN 并将调用重定向到 @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
}
}
这可能是与 this 类似的问题 - 使用 JDK 代理时找不到注释,因为您有 interface
.
将注解移至界面,或使用
@EnableRetry(proxyTargetClass = true)
我向那个 PR 添加了另一个提交来解决这个问题。
编辑
你好像理解错了@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
或者,您可能希望将重试置于断路器中,具体取决于您想要的行为。
我运行遇到@CircuitBreaker 没有重试的问题。
我有一个服务 class(例如 Class UserService 和方法名称 getUser),此方法调用另一个 Spring bean(例如 AppClient 和 execute),这反过来使调用远程服务(REST 调用)。 execute 方法用 Spring-Retry.
的 @CircuitBreaker 注释我已经在 rest 控制器中公开了对服务方法的调用(Class UserService 和方法名称 getUser),我使用 Postman 对其进行了测试。这是发生了什么——如果出现超时错误,它会调用@Recover 方法。但它不会重试三次调用远程服务(默认值)。
如果我通过 Postman 手动 运行 它 3 次,断路器状态变为 OPEN 并将调用重定向到 @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
}
}
这可能是与 this 类似的问题 - 使用 JDK 代理时找不到注释,因为您有 interface
.
将注解移至界面,或使用
@EnableRetry(proxyTargetClass = true)
我向那个 PR 添加了另一个提交来解决这个问题。
编辑
你好像理解错了@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
或者,您可能希望将重试置于断路器中,具体取决于您想要的行为。