WLPs MicroProfile (FaultTolerance) Тайм-аут Реализация не прерывает потоки?

Я тестирую реализацию отказоустойчивости (микропрофиля) Websphere Liberty. Поэтому я сделал простой REST-сервис с ресурсом, который спит 5 секунд:

 @Path("client")
 public class Client {

      @GET
      @Path("timeout")
      public Response getClientTimeout() throws InterruptedException {
          Thread.sleep(5000);
          return Response.ok().entity("text").build();
      }
 }

Я вызываю этого клиента в том же приложении в другом REST-сервисе:

 @Path("mpfaulttolerance")
 @RequestScoped
 public class MpFaultToleranceController {

      @GET
      @Path("timeout")
      @Timeout(4)
      public Response getFailingRequest() {
          System.out.println("start");
          // calls the 5 seconds-ressource; should time out
          Response response = ClientBuilder.newClient().target("http://localhost:9080").path("/resilience/api/client/timeout").request().get();
          System.out.println("hello");
      }
 }

Теперь я ожидаю, что метод getFailingRequest() истечет через 4 мсек и выдаст исключение. Фактическое поведение заключается в том, что приложение печатает "start", ждет 5 секунд, пока клиент не вернется, напечатает "hello", а затем выдает "org.eclipse.microprofile.faulttolerance.exceptions.TimeoutException".

Я включил дальнейшую отладочную информацию:

<logging traceSpecification="com.ibm.ws.microprofile.*=all" />

в server.xml. Я получаю эту информацию, что время ожидания зарегистрировано даже до того, как клиент называется! Но нить не прерывается.

(если кто-то скажет мне, как получить красивую трассировку стека здесь... я могу это сделать.)

Поскольку это очень простой пример: я что-то здесь не так делаю? Что я могу сделать, чтобы этот пример работал правильно.

Спасибо

Редактировать: Запуск этого примера на WebSphere Application Server 18.0.0.2/wlp-1.0.21.cl180220180619-0403) auf Java HotSpot(TM) 64-битная виртуальная машина сервера, версия 1.8.0_172-b11 (de_DE) с функциями webProfile-8.0, mpFaultTolerance-1.0 и localConnector-1.0.

Изменить: Решение, благодаря Энди МакКрайт и Azquelt. Поскольку вызов не может быть прерван, я должен сделать его асинхронным. Итак, вы получили 2 потока: первый, который вызывает второй поток с вызовом. Первый поток будет прерван, второй останется до завершения вызова. Но теперь вы можете продолжить обработку сбоев, открыть цепь и все в таком духе, чтобы предотвратить дальнейшие вызовы сломанной службы.

@Path("mpfaulttolerance")
@RequestScoped
public class MpFaultToleranceController {

    @Inject
    private TestBase test;

    @GET
    @Path("timeout")
    @Timeout(4)
    public Response getFailingRequest() throws InterruptedException, ExecutionException {
        Future<Response> resp = test.createFailingRequestToClientAsynch();
        return resp.get();
    }
}

И клиент звонит:

@ApplicationScoped
public class TestBase {

    @Asynchronous
    public Future<Response> createFailingRequestToClientAsynch() {
        Response response = ClientBuilder.newClient().target("http://localhost:9080").path("/resilience/api/client/timeout").request().get();
        return CompletableFuture.completedFuture(response);
    }
}

2 ответа

Решение

Это прерывает потоки, используя Thread.interrupt(), но, к сожалению, не все операции Java отвечают на прерывания потока.

Многие вещи реагируют на прерывания, создавая исключение InterruptedException (например, Thread.sleep(), Object.wait(), Future.get() и подклассы InterruptableChannel) но InputStreams и Sockets этого не делают.

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

Это особенно не интуитивно понятно, потому что клиент Liberty JAX-RS не отвечает на прерывания потоков, как упоминал Энди МакКрайт. Мы знаем, что это не очень хорошая ситуация, и мы работаем над тем, чтобы сделать ее лучше.

У меня такая же проблема. Для некоторых URL-адресов, которые я использую, тайм-аут отказоустойчивости не работает. В моем случае я использую RestClient. Я решил свою проблему, используя readTimeout () RestClientBuilder:

      MyRestClientClass myRestClientClass = RestClientBuilder.newBuilder().baseUri(uri).readTimeout(3l, TimeUnit.SECONDS) .build(MyRestClientClient.class); 

Одним из преимуществ использования этого элемента управления Timeout является то, что вы можете передать время ожидания в качестве параметра.

Другие вопросы по тегам