Vertx - threads are stuck while sending response back to client

602 views
Skip to first unread message

Kaluva S

unread,
Oct 12, 2022, 2:11:53 AM10/12/22
to vert.x

I'm using vertx-4.2.6 to build a proxy service which takes requests from clients (for ex: browser, standalone apps etc), invoke a single thirdparty server, gets the response and send the same response back to client who initiated the request.

In this process, I'm using shared Webclient across multiple requests, i'm getting response from thirdparty quickly (mostly in milli seconds) but sometimes the response is not returned back to client and stucks at ctx.end(response).

Whenever i restart my proxy server, it serves requests sometimes without any issues but time goes on, lets say by EOD, for new requests client seeing 503 error -service unavailable  I'm using one MainVerticle with 10 instances. I'm not using any worker threads.

Below is the pseudo code:

MainVerticle

DeploymentOptions depOptions = new DeploymentOptions(); depOptions.setConfig(config); depOptions.setInstances(10); vertx.deployVerticle(MainVerticle.class.getName(), depOptions); 

 ..... 

router.route("/api/v1/*") .handler(new HttpRequestHandler(vertx));


HttpRequestHandler:

public class HttpRequestHandler implements Handler<RoutingContext> {

    private final Logger LOGGER = LogManager.getLogger( HttpRequestHandler.class );

   
    private WebClient webClient;
   
    public HttpRequestHandler(Vertx vertx) {
        super(vertx);
        this.webClient=createWebClient(vertx);
    }

    private WebClient createWebClient(Vertx vertx) {
        WebClientOptions options=new WebClientOptions();
        options.setConnectTimeout(30000);
        WebClient webClient = WebClient.create(vertx,options);
        return webClient;
    }

    @Override
    public void handle(RoutingContext ctx) {
    ctx.request().bodyHandler(bh -> {
           
            ctx.request().headers().remove("Host");
           
            StopWatch sw=StopWatch.createStarted();
            LOGGER.info("invoking CL end point with the given request details...");
            /*
             * Invoking actual target
             */
            webClient.request(ctx.request().method(),target_port,target_host, "someURL")
                    .timeout(5000)
                    .sendBuffer(bh)
                    .onSuccess(clResponse -> {
                        LOGGER.info("CL response statuscode: {}, headers: {}",clResponse.statusCode(),clResponse.headers());
                        LOGGER.trace("response body from CL: {}",clResponse.body());
                        sw.stop();
                        LOGGER.info("Timetaken: {}ms",sw.getTime());  //prints in milliseconds
                       
                       
                       
                        LOGGER.info("sending response back to client...."); //stuck here
                        /*
                         * prepare the final response and return to client..
                         */
                        ctx.response().setStatusCode(clResponse.statusCode());
                        ctx.response().headers().addAll(clResponse.headers());
                       
                        if(clResponse.body()!=null) {
                            ctx.response().end(clResponse.body());
                        }else {
                            ctx.response().end();
                        }
                       
                        LOGGER.info("response SENT back to client...!!"); //not getting this log for certain requests and gives 503 - service unavailable to clients after 5 seconds..
                       
                    }).onFailure(err -> {
                        LOGGER.error("Failed while invoking CL server:",err);
                        sw.stop();
                       
                       
                        if(err.getCause() instanceof java.net.ConnectException) {
                            connectionRefused(ctx);
                        }else {
                            invalidResponse(ctx);
                        }
                   });
        });
Im suspecting issue might be due to shared webclient. But i'm not sure. I'm new to Vertx and i'm not getting any clue what's going wrong. Please suggest if there are any options to be set on WebClientOptions to avoid this issue.


Bruno F

unread,
Oct 12, 2022, 7:32:19 AM10/12/22
to vert.x
Can you try changing the value of the maxPoolSize option?
It defaults to 5 (= number of concurrent requests).

Sreeni

unread,
Oct 13, 2022, 1:37:35 AM10/13/22
to vert.x
Thanks for the suggestion. I increased to 100. Monitoring the application performance. Will update if there are still hiccups.

Sreeni

unread,
Oct 26, 2022, 1:40:01 AM10/26/22
to vert.x
Looks like problem is not solved. Instead of getting daily , now getting 503 for every 2 to 3days. Not sure  what else can be set to prevent this.

Bruno F

unread,
Oct 26, 2022, 4:50:20 AM10/26/22
to vert.x
Maybe it wasn't Vertx webclient hanging in first place, maybe the proxied backend you were calling was slow to respond (or maybe both)?
Now that you have increased the number of parallel requests to your proxied backend, maybe it is starting to reply 503 because it can't cope with the load?

Sreeni

unread,
Oct 27, 2022, 11:38:53 AM10/27/22
to vert.x
Okay .. will check with that thirdparty server team on this.

Sreeni

unread,
Nov 1, 2022, 5:05:48 AM11/1/22
to vert.x
they are saying my proxy service is not closing the connections after serving requests. But im using shared webclient, if i close the client , i wont be able to reuse the same client instance for next requests right?? How to terminate just connection after serving requests without closing the client?

Bruno F

unread,
Nov 1, 2022, 6:42:54 AM11/1/22
to vert.x
If you close the client, it seems reasonable to think you won't be able to reuse it.
When building the client, you can globally disable "keep alive" using WebClientOptions (or change the keep alive timeout if that can help).
If you're using HTTP 1 (I don't know HTTP/2), you can also use putHeader("Connection", "close") on a per-request basis before sending the request. But be careful if your proxy is blindingly propagating headers from the caller to the backend (way and back): I might be wrong but I wouldn't propagate the "Connection" header if I were you.
Please note that an HTTP client library (Vert.x WebClient here) not closing connections after receiving the response should not come as a surprise: the goal is to implement HTTP persistent connections (aka "keep alive") allowing better performance. That keep alive behavior is the default behavior in HTTP 1.1.

Sreeni

unread,
Nov 1, 2022, 8:02:01 AM11/1/22
to vert.x
Thanks a lot. Your comments really helping me to make progress on this. Just now i explored on keep alive timeout and idle timeout options on WebClientOptions. IdletTimeout i set as 30seconds (default is no timeout) and keepalive timeout also 20 seconds (default is 60seconds). Lets see if it improves the application performance. And you are right, I'm just simply forwarding the headers im receiving from that thirdparty server as is to client who made the request, so i dont want to change "Connection" header. 
Reply all
Reply to author
Forward
0 new messages