quarkus: Mutiny and Resteasy integration sometimes fails with "Attempted to do blocking IO from the IO thread"

Describe the bug

Often Multi returned to Resteasy causes exception, although both database and Kafka are executed in a worker thread.

Code:

@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.APPLICATION_JSON)
@RolesAllowed("file-upload")
public Uni<List<Long>> upload(
        @Nonnull @Context SecurityContext securityContext,
        Map<String, byte[]> files
) {
    return Multi
            .createFrom().iterable(files.entrySet())
            .onItem().produceMulti(entry -> extractFiles(securityContext.getUserPrincipal().getName(), entry))
            .concatenate()
            .onItem().invoke(fileEntity -> persist(fileEntity)).subscribeOn(Infrastructure.getDefaultWorkerPool())
            .emitOn(Infrastructure.getDefaultWorkerPool())
            .onItem().produceCompletionStage(fileEntity -> sendMessage(fileEntity)).concatenate()
            .collectItems().asList()
            .ifNoItem().after(Duration.ofSeconds(200)).failWith(
                    () -> new ServerErrorException("Kafka not responding", Response.Status.GATEWAY_TIMEOUT));
}

sendMessage returns CompletableFuture:

final CompletableFuture<Void> voidCompletableFuture = new CompletableFuture();
OutgoingKafkaRecord<Long, ProcessingStatus> message =
    KafkaRecord.of(fileEntity.getId(), status)
        .withAck(() -> {
          voidCompletableFuture.complete(null);
          return voidCompletableFuture;
        });
emitter.send(message);
return voidCompletableFuture.thenApply(void -> status.getId());

Exception:

[vert.x-eventloop-thread-2] [SynchronousDispatcher.java:545] - RESTEASY002020: Unhandled asynchronous exception, sending back 500: javax.ws.rs.ProcessingException: RESTEASY008205: JSON Binding serialization error java.lang.IllegalStateException: UT000126: Attempted to do blocking IO from the IO thread. This is prohibited as it may result in deadlocks

It seems that error does not happen when emmiter.send is used without the future.

Expected behavior

Resteasy should just execute the request as all blocking operations are moved to worker threads.

Actual behavior

Resteasy complaints about blocking operation.

To Reproduce Steps to reproduce the behavior:

  1. Return Multi with emmiter.send waiting for future to complete

Configuration

# Add your application.properties here, if applicable.

Screenshots (If applicable, add screenshots to help explain your problem.)

Environment (please complete the following information):

  • Output of uname -a or ver: Microsoft Windows [Version 10.0.19041.153]
  • Output of java -version: 1.8
  • GraalVM version (if different from Java):
  • Quarkus version or git rev: 1.3.0.Final
  • Build tool (ie. output of mvnw --version or gradlew --version): Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)

Additional context @cescoffier https://groups.google.com/forum/#!topic/smallrye/J4fEeQYfM5w

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 1
  • Comments: 32 (18 by maintainers)

Most upvoted comments

@akoufa yiu can use ‘Infrastructure.getDefaultExecutor()’

Yeah, i see the gzip interceptor which forces blocking IO.