-
Notifications
You must be signed in to change notification settings - Fork 30.3k
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
Process debug adapter messages in separate tasks; see #33822, #79196 #81403
Conversation
@isidorn Could you please take a look? This is another part of #81196. I did include a test which demonstrates the behavior. For manual testing, evaluate Unfortunately, I did not find a primitive from
|
@@ -540,4 +542,26 @@ suite('Debug - Model', () => { | |||
assert.equal(grandChild.getReplElements().length, 2); | |||
assert.equal(child3.getReplElements().length, 1); | |||
}); | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Love the tests.
} | ||
} | ||
} | ||
|
||
private processQueue(): void { | ||
const message = this.queue!.shift()!; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not understand why you need this.queue!
(I mean the explamation mark at the end)
this.queue
is never null and you properly initiazlie it to an empty array. So you should be always safe to access this.queue
.
As for the ! after the shift, I would prefer to just check if the message is there by if !(message) {return}
. Just looks safer to me.
@dgozman I like that all the changes are kept on the Couple of things:
fyi @weinand on the changes. Best described in @dgozman initial comment |
Thank you, @isidorn. Pushing this to October sounds good to me, this PR is riskier than average :) I will try to use the Queue as you suggested, will see whether it will be easier. |
Let's discuss this when I'm back from vacation. |
Assigning to @weinand so he does his review. I did an initial review. |
f583a7d
to
bacbfd2
Compare
I address the comments, tests still pass 🙂 |
Thanks a lot! This looks great to me and now is the perfect time to merge this (start of milestone). I @weinand does not oppose I will merge this in tomorrow. |
It doesn't unfortunately--I didn't root cause it earlier, but it looks like the main problem is actually that the terminated output is written on the parent debug session, whereas the test output comes from the child. Disregarding this bug, we actually do preserve order of output messages for a single debug session, but not across all debug sessions--and I'm not sure that we should: if one session is e.g. deadlocked and not sending variables, should we hold up the output of all other sessions? I was holding off pushing more on that for microsoft/debug-adapter-protocol#85, a DAP feature we need to resolve a separate problem. If we go with the implementation I suggested in that issue, then that will also solve microsoft/vscode-js-debug#122 by removing the async pathway. |
Ok, thanks for clariyfing. |
Common pattern when dealing with bidirectional channel is:
If we consider the other side of the cannel, it often sends events in between request and response:
This generates the following sequence of messages:
[someEvent, someCommandResponse]
, which is handled by the channel in the order ofsomeEvent, someCommandResponse
.However,
someEvent
is then dispatched synchronously (seeonSomeEvent
above), whilesomeCommandResponse
is handled through a promise (seeawait sendCommand
above). More general, various event handlers and command response handlers contain arbitrary promise chains of different lengths before being handled. This turns commands/events which did arrive in the right order during a singlejavascript task
- into handlers which run in absolutely different order due to different chains ofjavascript microtasks
.To guarantee the order of processing between various events and command responses, we can artificially insert
javascript task
boundaries between them. This ensures that anyjavascript microtasks
related to the first event/response handling will finish before the next event/response is processed, no matter how long the promise chain was, thanks to the javascript tasks spec.