0

In one of the projects that I'm working on I register routes onto the Router dynamically like below.

vertx.eventBus().consumer("REGISTER_ROUTE", handler -> {
      JsonObject message = (JsonObject) handler.body();
      HttpMethod method = HttpMethod.valueOf(message.getString("method"));
      router.route(method, message.getString("url"))
        .order(1)
        .handler(cxt -> cxt.json(new JsonObject().put("message", "This works..!!")));
    });

And this event is triggered from another verticle like this

vertx.eventBus().send("REGISTER_ROUTE",
        new JsonObject()
          .put("url", "/test-route")
          .put("method", "GET")
      );

Issue is that on windows machine this almost always works. But on a testing linux instance on AWS

  • I generally receive a 404 Not Found response instead of the actual response
  • Or I get 2 success response(200) and one 404
  • Or I get Two 404 and 1 success response

Last two of the scenarios not very sure what's the correlation to number 3(since this success/error response seems to refresh on a cycle of 3 subsequent requests). Thought it could be to number of instances of the server verticle. But modifying the instance count doesn't change this behavior either.

I have a custom error handler for 404 registered like below

router.errorHandler(404, routingContext -> {
      LOGGER.info("HTTP-404 Error Handler invoked");
      LOGGER.info("Router :" + router.toString() + " Routes Size: " + router.getRoutes().size());
      JsonObject error = new JsonObject()
        .put("error", "Resource not found");
      routingContext.response()
        .setStatusCode(404)
        .putHeader(HttpHeaders.CONTENT_TYPE, "application/json")
        .end(error.toBuffer());
    });

Whenever a 404 response is received I could see from the logs that router states does show there is a route declared with the given PATH and HTTP method combination.

I have tried registering route using the HTTP method specific syntax like router.get(url), that didn't seem to make any difference either.

Vert.x Version: 4.2.7

JDK: Eclipse Temurin 11.0.14.1+1

OS: Centos 7 on EC2

Problem is that issue doesn't occur always so it's becoming more and more difficult to identify the root cause and fix it.

Please let me know if there is anything that is wrong/missing in this. Also I have created a sample project here. This is a close replica of what I have on my actual project. Note: The issue didn't generally occur to me on Windows (for whatever reasons).

Hegdekar
  • 1,147
  • 1
  • 13
  • 16

2 Answers2

0

In App class, 4 instances of each verticle are deployed.

vertx.deployVerticle(Server.class.getName(), new DeploymentOptions().setInstances(4))
      .compose(server -> {
        return vertx.deployVerticle(RouteRegistration.class.getName(), new DeploymentOptions().setInstances(4))
          .onSuccess(id -> LOGGER.info("Application started Successfully"))
          .onFailure(LOGGER::catching);
      });vertx.deployVerticle(Server.class.getName(), new DeploymentOptions().setInstances(4))
      .compose(server -> {
        return vertx.deployVerticle(RouteRegistration.class.getName(), new DeploymentOptions().setInstances(4))
          .onSuccess(id -> LOGGER.info("Application started Successfully"))
          .onFailure(LOGGER::catching);
      });

This means that:

  • a shared HTTP server will be created and incoming connections load-balanced between instances of the Server verticle.
  • messages sent from RouteRegistration verticle instances will be load-balanced between consumers (eventBus.send is point-to-point).

Consequently, connections will be handled by different routers with different setups.

On your local machine, I don't know why it works, perhaps you deploy a single instance?

Anyway, to fix the issue, you must have the same router configuration in every router instance, so the RouteRegistration must publish the message so that every consumer instance gets it:

vertx.eventBus().publish("REGISTER_ROUTE",
      new JsonObject()
        .put("url", "/test-route")
        .put("method", "GET")
    );
tsegismont
  • 8,591
  • 1
  • 17
  • 27
  • I assumed this and had tried it as well. I'm sorry I haven't updated that in the sample reproducer code. Will update it. But that didn't fix either. Also since the Router is declared as static isn't that a single copy across all the Server verticle instances? so despite the event being a send it still gets registered across all the instances isn't it? And while debugging today observed scaling the instance to a 4 core vCPU the issue doesn't replicate , I'm clueless now what to check for. – Hegdekar May 16 '22 at 12:50
  • I had not noticed the router was declared `static`. That is not good: it is going to be updated concurrently but it is not thread-safe. You should create a `Router` instance per verticle instance. – tsegismont May 16 '22 at 16:35
  • Changing `Router` to non-static and changing the event to `publish()` together fixed my problem. But even now not very sure how it was working on the dev environment. Couldn't figure out what caused it to work even with multiple instances. But thanks a lot for the help. – Hegdekar May 18 '22 at 05:21
  • Thread safety issues may or not may be apparent depending on the system conditions. – tsegismont May 18 '22 at 07:45
0

I had the same problem, and switched back to deploy (Supplier splv ,DeploymentOptions opt ) , and it worked 100% . example : vertx.deployVerticle(()->{ new VerticleFirst(router,...); }, deployOptions );

TungJa
  • 1
  • 2
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Dec 19 '22 at 13:54