2

I'm testing the websphere liberty's fault tolerance (microprofile) implementation. Therefore I made a simple REST-Service with a ressource which sleeps for 5 seconds:

 @Path("client")
 public class Client {

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

I call this client within the same application within another REST-service:

 @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");
      }
 }

Now I'd expect that the method getFailingRequest() would time out after 4 ms and throw an exception. The actual behaviour is that the application prints "start", waits 5 seconds until the client returns, prints "hello" and then throws an "org.eclipse.microprofile.faulttolerance.exceptions.TimeoutException".

I turned on further debug information:

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

in server.xml. I get these information, that the timeout is registered even bevor the client is called! But the thread is not interrupted.

(if someone tells me how to get the stacktrace pretty in here... I can do that.)

Since this a very basic example: Am I doing anything wrong here? What can I do to make this example run properly.

Thanks

Edit: Running this example on WebSphere Application Server 18.0.0.2/wlp-1.0.21.cl180220180619-0403) auf Java HotSpot(TM) 64-Bit Server VM, Version 1.8.0_172-b11 (de_DE) with the features webProfile-8.0, mpFaultTolerance-1.0 and localConnector-1.0.

Edit: Solution, thanks to Andy McCright and Azquelt. Since the call cannot be interrupted I have to make it asynchronous. So you got 2 threads: The first an who invoke the second thread with the call. The first thread will be interrupted, the second remains until the call finishes. But now you can go on with failure handling, open the circuit and stuff like that to prevent making further calls to the broken service.

@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();
    }
}

And the client call:

@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);
    }
}
4

2 回答 2

3

它确实使用 中断线程Thread.interrupt(),但不幸的是,并非所有 Java 操作都响应线程中断。

Thread.sleep()许多事情确实通过抛出 InterruptedException(如、和 的子类)来响应中断,Object.wait()但InputStreams 和 Sockets 不会。Future.get()InterruptableChannel

我怀疑您(或您用来发出请求的库)正在使用不可中断的 Socket,因此您看不到您的方法提前返回。

这特别不直观,因为 Liberty 的 JAX-RS 客户端不会像 Andy McCright 提到的那样响应线程中断。我们知道这不是一个很好的情况,我们正在努力让它变得更好。

于 2018-09-20T16:37:07.820 回答
0

我有同样的问题。对于我使用的某些 URL,容错超时不起作用。就我而言,我使用 RestClient。我使用 RestClientBuilder 的 readTimeout() 解决了我的问题:

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

使用此 Timeout 控件的一个优点是您可以将超时作为参数传递。

于 2021-07-01T23:14:42.980 回答