Spring-retry - @Circuitbreaker не повторяется - PullRequest
0 голосов
/ 23 октября 2018

Я сталкиваюсь с проблемой, когда @CircuitBreaker не повторяет попытку.

У меня есть класс обслуживания (например, Class UserService и имя метода getUser), этот метод вызывает другой bean-компонент Spring (например, AppClient ивыполнить), который, в свою очередь, делает вызов удаленной службе (вызов REST).метод execute аннотирован с помощью @CircuitBreaker из Spring-Retry.

Я выставил вызов метода службы (Class UserService и имя метода getUser) в контроллере rest, и я протестировал его с помощью Postman.вот что происходит - в случае ошибки тайм-аута он вызывает метод @Recover.Но он не будет повторять вызов удаленной службы три раза (значение по умолчанию).

Если я вручную запустлю его 3 раза через Postman, состояние автоматического выключателя изменится на ОТКРЫТО и перенаправит вызовы в метод @Recover и после сбросатайм-аут, он возобновляет звонки на удаленный сервис.

Кроме того, я заменил @CircuitBreaker на @Retryable, и он делает вызов три раза (значение по умолчанию).Я использую версию 1.2.1.RELEASE с пружинным повтором и версию 1.6.2 aspectjtools.

Почему бы не повторить попытку с @CircuitBreaker ??Я хотел бы иметь обе функции выключателя и Retry.Согласно документации, @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 Ответ

0 голосов
/ 23 октября 2018

Это, вероятно, проблема, аналогичная этой - аннотация не найдена при использовании прокси-сервера 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

Или, возможно, вы захотите включить повтор в автоматическом выключателе, в зависимости от того, какое поведение вы хотите.

...