javawebsphere-libertyfault-toleranceopen-libertymicroprofile

WLPs MicroProfile (FaultTolerance) Timeout Implementation does not interrupt threads?


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

Solution

  • It does interrupt threads using Thread.interrupt(), but unfortunately not all Java operations respond to thread interrupts.

    Lots of things do respond to interrupts by throwing an InterruptedException (like Thread.sleep(), Object.wait(), Future.get() and subclasses of InterruptableChannel) but InputStreams and Sockets don't.

    I suspect that you (or the library you're using to make the request) is using a Socket which isn't interruptible so you don't see your method return early.

    It's particularly unintuitive because Liberty's JAX-RS client doesn't respond to thread interrupts as Andy McCright mentioned. We're aware it's not a great situation and we're working on making it better.