Vert.x async to sync blocks event-loop-thread

130 views Asked by At

In my router-handler I need to await for the event-bus request to make it synchronous.

The code looks like so:

router.patch '/api/check' handler this::validateField

void validateField( RoutingContext rc ) {
  log.info 'validate start'

  CountDownLatch countDownLatch = new CountDownLatch( 1 )
    
  Future<Message> fut = vertx.eventBus().request( 'validate', 'msg' ).onComplete{ countDownLatch.countDown() }
    
  boolean done = countDownLatch.await 4, TimeUnit.SECONDS

  if( !done )
    rc.json 'service.failure'
  else if( fut.failed() ){
    ReplyException cause = (ReplyException)fut.cause()
    rc.json ReplyFailure.RECIPIENT_FAILURE == cause?.failureType ? cause.message : 'service.failure'
  }else
    rc.json 'ok'
}

The code above produces the following log output:

[vert.x-eventloop-thread-2] 10:11:03.940 INFO  my.Klass - validate start
[vertx-blocked-thread-checker] 10:11:06.297 WARN  i.v.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-2,5,main] has been blocked for 2357 ms, time limit is 2000 ms
[vertx-blocked-thread-checker] 10:11:07.298 WARN  i.v.core.impl.BlockedThreadChecker - Thread Thread[vert.x-eventloop-thread-2,5,main] has been blocked for 3357 ms, time limit is 2000 ms

As you can see, the countDownLatch blocks the event-loop-thread for 4 seconds before it's timeout occurs and completes unconditionally.

It doesn't matter if the EB-consumer is reachable and what it responses. The thread simply gets blocked.

The same behavior occurs with java's CompletableFuture.

Now, if I change the handler to blockingHandler in 1st line, the whole thing starts to work just as expected:

router.patch '/api/check' blockingHandler this::validateField

The code reacts properly on NO_HANDLERS and on valid consumer requests and is waiting as long as needed.

Why does it behave like that?

1

There are 1 answers

0
tsegismont On BEST ANSWER

It doesn't matter if the EB-consumer is reachable and what it responses. The thread simply gets blocked.

While the event loop is blocked waiting for the future to complete, it cannot handle the event that completes the future.

Now, if I change the handler to blockingHandler in 1st line, the whole thing starts to work just as expected

In this case, it's one of the worker pool threads which is blocked waiting for the future to complete, and then the future is completed by the event loop thread.