Webclient and worker verticles

287 views
Skip to first unread message

Alessandro Chacon

unread,
Dec 22, 2020, 5:54:18 PM12/22/20
to vert.x
Hi,

I'm using Vertx 3.7.1. I have a worker verticle running that creates a webclient and performs requests on incoming eventbus events. For some reason the web requests are done in a vertx pool thread but the handle replies in a different thread than the caller all the time. 
It's always different. I would have expected that the handler uses the same context (or thread) as the caller. 
The same doesn't happen with event bus handlers, there the context is the same for caller and handler.

Anybody has an explanation why this could be happening?

Cheers

Julien Viet

unread,
Dec 26, 2020, 7:29:17 AM12/26/20
to vert.x
Hi,

this behavior can happen with Vert.x 3 if you are sharing the WebClient between several verticles.

The main reason is that the event-loop is associated with the HTTP connection that is pooled.

In Vert.x 4 we have decoupled this and you can use a WebClient / HttpClient and the request/response should use the expected event loop.

Julien





--
You received this message because you are subscribed to the Google Groups "vert.x" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vertx+un...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/vertx/c5d3d038-9194-42a4-a2d2-e8e6046885cen%40googlegroups.com.

Alessandro Chacon

unread,
Dec 28, 2020, 4:12:11 AM12/28/20
to vert.x
Hi Julien, 

Thanks for the answer. I checked that before and I'm quite sure I'm not sharing the webclient between verticle. Every verticle that I have extends an abstract class that creates the webclients. Is there any other possibility where such issue happens? or maybe there is an implicit sharing being done by Vertx? 

Julien Viet

unread,
Dec 30, 2020, 7:03:27 AM12/30/20
to vert.x
Hi,

in that case it might be a bug, and if you provide a reproducer we can have a look at it.

Julien

Alessandro Chacon

unread,
Dec 30, 2020, 8:49:04 AM12/30/20
to vert.x
Hi Julien, thanks for the help!

A simple verticle does the trick in my case:

```
public class TestVerticle1 extends AbstractVerticle {

private WebClient webClient;

@Override
public void start(Future<Void> startFuture) {
WebClientOptions webClientOptions = new WebClientOptions();
webClientOptions.setSsl(false);
webClientOptions.setConnectTimeout(5000); // msec
webClientOptions.setIdleTimeout(30); // sec
webClient = WebClient.create(vertx, webClientOptions);

vertx.eventBus().consumer("TEST", t -> {

Future<HttpResponse<Buffer>> future = Future.future();
webClient.get(8080, "http://localhost", "/").send(future);
System.out.println("This thread called is creating the http request: " + Thread.currentThread());

future.setHandler(r -> {
System.out.println("This thread is handling the http response: " + Thread.currentThread());
System.out.println(r);
});

});

vertx.setTimer(1000L, t -> {
vertx.eventBus().send("TEST", "");
});
}
}
```

This will print:

This thread called is creating the http request: Thread[vert.x-worker-thread-11,5,main]
This thread is handling the http response: Thread[vert.x-worker-thread-12,5,main]
Future{cause=failed to resolve 'http://localhost' after 3 queries }

That Verticle was initiated as a worker verticle:

```
Vertx.clusteredVertx(options, res -> {
if (res.succeeded()) {
Vertx vertx = res.result();
vertx.deployVerticle(new TestVerticle1(), new DeploymentOptions().setWorker(true), result -> {
if (result.succeeded()) {
LOGGER.info("AccountVerticle deployment complete.");
} else {
LOGGER.error("AccountVerticle deployment failed!", result.cause());
}
});
} else {
// failed!
LOGGER.error("Vert.x cluster manager start failed", res.cause());
}
});
```

I attach the code in case needed.
test.zip

Alessandro Chacon

unread,
Jan 6, 2021, 8:57:29 AM1/6/21
to vert.x
I tried the same using vertx 4.0.0 and I got the same result. I expect the handler to be handled in the caller thread, (even if it's a worker verticle), but maybe my assumption is wrong. If so, is there any way to force the handler to run in the caller thread?

Julien Viet

unread,
Jan 11, 2021, 2:32:22 AM1/11/21
to vert.x
can you provide a small reproducer ?

Message has been deleted
Message has been deleted
Message has been deleted
Message has been deleted

Alessandro Chacon

unread,
Jan 11, 2021, 6:11:22 AM1/11/21
to vert.x

Julien Viet

unread,
Jan 12, 2021, 4:52:42 AM1/12/21
to vert.x
Hi Alessandro,

actually what you are observing is normal and I did provide you an initial wrong response.

As you are using a worker verticle, it is normal to have different worker threads running the Verticle. Actually it has to be like this for performance reason, otherwise it would mean that a thread is pinned to a Verticle and running a Verticle task means waiting for this thread to be available.

Instead what happens is that a thread is chosen from the worker thread pool to run the Verticle which is why you don't observe the same thread.

However the context will remain the same when the verticle is used and most importantly Vert.x will serialize the tasks executed for this Verticle (context), so if two tasks are for this Verticle concurrently, the two tasks are added to a queue and they will be executed sequentially one after the other.

This sequential execution gives you the guarantee of exclusion, when a worker verticle is executed it can modify Verticle private state and this state won't be modified concurrently. Also the execution will make sure that the modifications done by one of the worker thread will be visible by the other worker threads executing other tasks later.

Julien













Alessandro Chacon

unread,
Jan 13, 2021, 5:44:36 AM1/13/21
to vert.x
Hi Julien,

Thanks for the complete answer! I really appreciate it.

I wonder what's the best way to achieve what I want (a consistent thread use), as my application consists on many API calls composed, it seems that only using a Standard Verticle I will be able to achieve that.
I'm also curious about the design decision of not using the same worker thread: as threads are selected on a round robin fashion, the same performance problem can occur if the next thread to be selected is already busy with another long standing operation. As far as I know Vertx is not smart when choosing the threads that are "available" and the "executing" ones. Or am I wrong?

Probably I should transform my architecture to rely less on Worker Verticles as I might be improperly using them.
Perhaps you can offer some suggestions on this.

Julien Viet

unread,
Jan 14, 2021, 4:18:06 PM1/14/21
to vert.x
Hi,

the same thread is not reused for worker for performance reason. If a worker thread would be pinned to a Verticle, then calling the Verticle could wait long time before the same worker thread is available.

That being said, if that's not the same worker thread, you will get the same concurrency guarantees as if it were the same thread.

Going away from worker is also something we advocate, specially on the critical path of your application.

Julien


Reply all
Reply to author
Forward
0 new messages