Skip to content
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

DuplicatedContext can cause unexpected behavior #3790

Closed
Gattag opened this issue Feb 5, 2021 · 6 comments
Closed

DuplicatedContext can cause unexpected behavior #3790

Gattag opened this issue Feb 5, 2021 · 6 comments
Assignees
Labels
Milestone

Comments

@Gattag
Copy link

Gattag commented Feb 5, 2021

The following code will run a bunch of blocking tasks all with ordered=true

public static void main(String[] args){
Context context0 = Vertx.vertx().getOrCreateContext();
context0.runOnContext(ignored0 -> {
	Vertx vertx = Vertx.currentContext().owner();
	vertx.eventBus().consumer("eb_address", m -> runTask(m.body().toString()));
	runTask("Task 1");
	runTask("Task 3");
	vertx.eventBus().publish("eb_address", "Task 2");
	vertx.setTimer(1, t -> {
		runTask("Task 4");
		vertx.eventBus().publish("eb_address", "Task 5");
	});
});
}

public static void runTask(String name){
        Vertx.currentContext().executeBlocking(promise -> {
	        System.out.println(name + " start");
	        try {
		        Thread.sleep(1000);
	        }catch(Exception e){
		        promise.fail(e);
		        return;
	        }
	        System.out.println(name + " done");
	        promise.complete();
        }, true);
}

This is the output:

Task 1 start
Task 2 start
Task 5 start
Task 1 done
Task 3 start
Task 2 done
Task 5 done
Task 3 done
Task 4 start
Task 4 done

Given that ordered=true, the output is odd, as conventional wisdom (and the documentation) would say that for any Task n start the message that should always follow it is Task n done. Of course ordering is only the case when the calls take place within the same context, and they all are called from the same context. Right?
I know that's not the case, but for any person that hasn't read the implementation, they should reasonably expect that everything that I wrote above is all run from the same context. That's the core of this issue, certain handlers are called with a DuplicatedContext and it causes unusual behavior because it creates a view of the parent context with the blocking TaskQueue being independant of the parent. Also, these side effects are completely undocumented.

I understand why DuplicatedContext exists, and I also know why we made the DuplicatedContext use its own TaskQueue, but I don't think the different TaskQueue was a good idea. It will cause issues for developers that will not be discovered immediately and in its current form make implementing the scheduler for RxJava imposible (For reasons why see: vert-x3/vertx-rx#245 (comment)) Personally I think it should be removed, and jdbc-client should revert back to the old solution (it appears to be the only thing that should use TaskQueue, but it doesn't look like it was properly implemented, see: vert-x3/vertx-jdbc-client#203 (comment)). Even though that is what I think, I don't think that is something that is going to happen, so I have a simpler solution. Do not create a seperate TaskQueue unless explicitly specified. This way the DuplicatedContext behaves exactly like its parent for all actions (though of course the localData map is not preserved between the two)

I'm already busy on a PR to make a couple of changes around DuplicatedContext

@vietj vietj added this to the 4.0.3 milestone Feb 5, 2021
@tsegismont
Copy link
Contributor

I also know why we made the DuplicatedContext use its own TaskQueue

Can you explain why? This sounds like a bug to me. DuplicatedContext shouldn't have its own task queue but share it with the parent Context.

Am I missing something @vietj ?

@Gattag
Copy link
Author

Gattag commented Feb 5, 2021

@tsegismont This is what vietj said to me on the matter

in Vert.x JDBC client the legacy API we had to use a workaround that was limiting scalality
because the JDBC connection was using execute blocking
and at this moment there was not task queue
it means that all connections were serialized for a given event loop
so we added a work around with task queue
each connection has a task queue and was providing it to execute blocking
so worker action execution for JDBC waas serialized per connection
when we did Vert.x 4 we introduced Context duplicate to tracing
and it was actually solving the issue with JDBC
and we could remove the tas kqueue per connection
because now each duplicate has its own task queue
and things are naturally ordered
I think the test I did is incomplete though

@vietj
Copy link
Member

vietj commented May 7, 2021

it is fine for duplicate context to have its own task queue because this is what most user will expect when they do schedule messages from an HTTP request.

@vietj
Copy link
Member

vietj commented May 7, 2021

but indeed I'm seing that might be an issue for ppl to reason about things.

@vietj
Copy link
Member

vietj commented May 7, 2021

the intent of this change is that if you use execute blocking from a scope that is a request or a message received then each is ordered according to the current activity.

if that's used like in the example (which seems unlikely in practice) then it does not give the expected results because of the context duplicate.

perhaps there should be a third mode that allows to have ordering for this:

  • deployment ordering (context like in 3)
  • activity ordering (http request, event bus message)
  • unordered

@vietj
Copy link
Member

vietj commented May 27, 2021

#3950

@vietj vietj closed this as completed May 27, 2021
@vietj vietj added the bug label May 27, 2021
@vietj vietj self-assigned this May 27, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants