DEV Community

Azizul Haque Ananto
Azizul Haque Ananto

Posted on

I have built an async to sync service using Vert.x event bus; please review the code and suggest better approaches

TLDR; Please visit here - https://github.com/Ananto30/vertx-async-gateway and review the code.

I have used ConcurrentHashMap to keep track of the requests. And assuming each async request should have a unique identifier that can be used to track it when we get the callback in a webhook.

Using this code, one can write new endpoints that will be calling third parties who are async (send the response in a callback URL). So when a call is received from a user, the response will be put in the ConcurrentHashMap against the identifier and block the request using the blocking handler of vertx (the response is not end()). Then a callback will be received in the callback endpoint and an event will be published in the bus. Another verticle will take the event and find it from the hashmap and end() the result to that specific request.

Is this code seems good enough for this purpose?

Top comments (2)

Collapse
 
jonastauliensolutions profile image
Jonas Taulien • Edited

Hi Azizul, I'm a Vert.x Coach and your post popped up in my Google Alert :)

I had a quick look and would like to give you some comments:

  • Regarding your Store-class: Vert.x has built-in Support for sharing data between Verticles (vertx.io/docs/vertx-core/java/#_us...). The SharedData API also allows you to share data between multiple instances of the same Vert.x application if you run them inside a cluster (vertx.io/docs/vertx-core/java/#_cl...). Keep in mind, that you can only use the SharedData API with immutable data, so it might not be the right tool for the job for your use-case. But also keep in mind, that you will never be able to scale your current solution to multiple, concurrently running instances (of the application).
  • Regarding the ExampleHandler/CommonAsyncHandler: It almost always leads to a more elegant software design to use delegation instead of extension. So convert the CommonAsyncHandler to a service, that each synchonous enpoint uses.
  • Write tests
  • You may want to use the Vert.x API for RxJava 2 (vertx.io/docs/vertx-rx/java2/) to avoid working with Promises and Futures
  • When I read your DevApp-class, It seems that there is a misunderstanding regarding the clustered mode. You only need the clustered Vert.x if you want to start the same application multiple times in some cloud environment (and you want those instances to talk to each other by using the event bus). If you only want to start multiple instances of one verticle in the same application (and want those to communicate with each other inside of that application), use

    vertx.deployVerticle(
        () -> new MainVerticle(), 
        new DeploymentOptions().setInstances(5)
    )
    

Just leave a reply if you have any questions :)

Collapse
 
ananto30 profile image
Azizul Haque Ananto

Hi Jonas, Thanks a lot for your response! Happy to see an expert's comment.

I am really new to the Vertx world and learning still. Please guide me if I'm wrong.

Regarding the Store class, I had to keep track of the requests which I've received from clients, so later I can send the response to appropriate ones. So, there's not much option here. ConcurrentHashMap can ensure concurrent reads, which is important as I'm using an event loop based server. Why can't I use concurrent running instances? Each instance will get its own store and as I am just broadcasting the callback to every instance one of them will have the record and will send the response, eventually I tested this. Is there anything I'm missing?

About the second point, I've tried to follow the open-closed principle of SOLID. So I thought people can extend the CommonAsyncHandler if needed. But then again, your suggestion makes sense too. And also SOLID is more of an OOP pattern, not so functional.

I MUST write tests, that's a deficiency of mine :(

I didn't know about the RxJava API. Thanks!

And about the last point - oops I forgot to change those comments. Yes I learned more about the cluster in the docs later and fully agree with you.

I have some questions if you get time to guide -

  1. What are the ways for request validation? For REST(Json) mostly. (Except the json-schema)
  2. How can I ensure chaining for blocking tasks? Is it same as WebFlux? (using map, flatmap etc)
  3. Is it a good idea to serve multiple instances of the same application in one docker image? Like if I run 2 instances of the above app in the same docker image, can I ensure more fault tolerance in a way that if one instance dies for any reason another one will serve.
  4. What are better logging ways rather using the Slf4j or logback?
  5. What is the preferred way to call the DB? By chaining or using the event bus? (For writes mostly we can use the bus, but for reads what's the preferred way?)

Thanks a lot for your time and explanations!