Vertx-web: multiple verticle instances as REST service with routingContext.next()

Created on 19 May 2016  路  7Comments  路  Source: vert-x3/vertx-web

Version

  • vert.x core: 3.2.1
  • vert.x web: 3.2.1

    Context

Hello,

I have a problem possible bug with multiple deployed instances of a verticle that is used as a REST endpoint. The service will receive every request and sanitize the payload. Then the next matching route (router.next()) will be called.

The Sanitizer verticle do something like this:
this.router.post("/*").handler(routingContext -> { // do something routingContext.next(); }

This Sanitizer verticle is deployed several times:
deploymentOptions.setInstances(5); this.vertx.deployVerticle(verticleName, deploymentOptions);

We use for all verticles the same router to go through all matching routes with routingContext.next(). For every request our Sanitizer is called, but it is called 5 times because it is deployed 5 times. Vert.x didn't notice, that麓s the same verticle which is called multiple times. I want that the Sanitizer verticle is only called once and then the next route (e.g. /test/test).

Is this a bug in vert.x or should I handle the router in a different way?

Example of verticle (The Runner.mainRouter is initialized once in Runner class):

`public class App extends AbstractVerticle {

public static void main(final String[] args) {
Runner.run(App.class);
}

@Override
public void start() {

Runner.mainRouter.get("/rest/*").handler(rc -> {
    System.out.println("sanitizer " + this);
    rc.next();
});

vertx.createHttpServer().requestHandler(Runner.mainRouter::accept).listen(8090);

}
}`

question

Most helpful comment

Think of a verticle as something that encapsulates a service. In your case, the sanitizer is not a separate service, it's just a handler that's used, along with other handlers to compose your web service, so it doesn't really make sense to put it in its own verticle.

It makes sense to create new verticles if the thing has a separate life cycle and it makes sense to deploy it and scale it independently.

All 7 comments

Don't share a Router between verticles - each verticle instance should have its own Router instance.

Hi purplefox,

thanks for your answer. If I have a separate router for each verticle only one verticle (with the shortes matching route) will be called. The routingContext.next() has no effect! So if the the example above use its own created router and I have another verticle which is deployed (see following example), only the sanitizer verticle is called.

Example, another verticle in addition:
`@Override
public void start() {
Router router = Router.router(vertx);

    router.get("/rest/hello").handler(rc -> {
        System.out.println("hello " + this);
        rc.response().end();
    });

    vertx.createHttpServer().requestHandler(router::accept).listen(8090);
}`

Then I try to reach: _localhost:8090/rest/hello_

If I have both verticles deployed only the "sanitizer" verticle will be called. The /rest/hello is never reached. Thats why I use only one router. Is there another way to do this?

I guess I don't understand why your sanitizer needs to be in its own verticle.

If you find yourself sharing Routers between verticle instances that's an anti-pattern. They were never designed to be used this way.

Thanks for this! Its not documented that each verticle should use its own router.

After your comment and some documentation inspection:
May I have misunderstood the verticle concept. Is it the right way to implement the sanitizer (or authentication and something like this) as a handler and add it to each router in each verticle?
Like this:
router.route("/private/*").handler(basicAuthHandler);

Is each verticle encapsulated and closed to the other verticles? In this fact it is not possible to go to the next route (routingContext.next()) over multiple verticles, because each verticle has its own router?

In the moment I developed the sanitizer and authentication as an own verticle and handle them with one singelton router.

Thanks in advanced.

Typically you will have a single verticle which represents your "server" or "microservice".

That verticle will maintain a router which contains all the handlers to do the things you want.

(BTW None of the examples in the examples repo share routers between verticle instances).

Think of a verticle as something that encapsulates a service. In your case, the sanitizer is not a separate service, it's just a handler that's used, along with other handlers to compose your web service, so it doesn't really make sense to put it in its own verticle.

It makes sense to create new verticles if the thing has a separate life cycle and it makes sense to deploy it and scale it independently.

Thank you very much. I think I have to refactor my architecture now and right some handlers not verticles. ;)

Was this page helpful?
0 / 5 - 0 ratings