-
Notifications
You must be signed in to change notification settings - Fork 535
Fix thread-safety of RouteImpl #739
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
When multiple concurrent requests is processed by the same route at the same time, due to the fact that the RouteImpl instance is shared across multiple requests, it creates a thread-unsafe situation. The main cause is that actualHandlerIndex and actualFailureHandlerIndex are states of a request, not the state of the route instance itself. Moved those two indexes into RoutingContext instead since that is the place where the state belonging to a request lives.
have you observed this issue ? a route should be single threaded and at most one request at a time should be processed |
Not necessarily. The vertx event loop may be single-threaded, but each handler are free to do whatever they want, including spawn a thread, and in that thread, call RoutingContext.next, which in turn increase the RouteImpl.actualHandlerIndex.
In our case, we use RxJava 2. One of the handler is Single.fromCallerable(....).subscribeOn(Schedulers.io()).subscribe((v, ex)-> context.next());
This piece of code would call RoutingContext.next() in RxJava’s io threadpool, and is causing racing conditions.
|
I don't know if the solution is valid or not (I haven't checked) however I'm concerned by the fact that the index seems to be internal and should not be exposed on the |
Agree that ideally we should not expose these as part of the public RoutingContext. I did not spend too much time on reading the code to see if it is OK to cast it to RoutingContextImpl or RoutingContextImplBase. |
Moved them into RoutingContextImplBase
I removed the methods from RoutingContext and moved them into RoutingContextImplBase. Sounds reasonable? |
This is related #729 |
Hi @visualage , I'm the guy that have created this problems 😄 I was working on a fix similar to yours and for me sounds good. I'm writing some tests to check your solution. I update you ASAP |
we need tests indeed for this patch |
Ok so I've created a pr inside @visualage 's fork. It has tests for:
I've also switched indexes to AtomicInteger to don't occur in other bugs |
Added some tests for multiple handlers
@slinkydeveloper, your PR is merged into my fork. |
@slinkydeveloper / @vietj is the current fix going to be a part of |
Thank you for giving this attention, @slinkydeveloper |
I've added another test, for me this pr is ok 😄 |
@slinkydeveloper Looks like its still not fixed. I am using 3.5.3 with this code asn its still failing with the same error
Trace:
|
Your exception tells that your body handler is too late to process the request body. Body handling must start running on the same call that received the request. Any async call in between will render this exception. Check the manual for this, either call the handler sooner or pause and resume the request on demand. |
@pmlopes I think you are right about being late for processing the request. I tried pause and resume methodology but didn't work. The intention is to process the request as a stream in parallel and if i go with vertx standards and use the single thread to read the body then I am not able to scale the server and I dont want to go the way of having multiple verticles. I think its still the multi threading issue with router implementation , I say so because if I replace the router with my simple implementation then the above code works fine. |
When multiple concurrent requests is processed by the same route at the same time, due to the fact that the RouteImpl instance is shared across multiple requests, it creates a thread-unsafe situation. The main cause is that actualHandlerIndex and actualFailureHandlerIndex are states of a request, not the state of the route instance itself.
Moved those two indexes into RoutingContext instead since that is the place where the state belonging to a request lives.