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

11685: Restore cancellation token behavior #11693

Merged
merged 1 commit into from
Sep 27, 2022

Conversation

tortmayr
Copy link
Contributor

What it does

Ensure that cancelling an RPC call does not result in an automatic rejection on the calling side. Instead the token is passed to the receiving side and handed there. This restores the cancellation strategy that was used with the old json-rpc architecture (prior to 1.28)

Contributed on behalf of STMicroelectronics.
Fixes #11685

How to test

  • Implement a frontend service that calls a backend service, provide a cancellation token, and cancel the action immediately.
  • Implement logic on the backend to handle cancelation and return some kind of default / partial result.
  • The (partial) return from the backend should be received on the frontend. The call should not get rejected.

The simple service that I used for testing is available here:
https://github.com/eclipsesource/theia/tree/cancelation-token-test

Review checklist

Reminder for reviewers

Comment on lines 133 to -137
// args array and the `CANCELLATION_TOKEN_KEY` string instead.
const cancellationToken: CancellationToken | undefined = args.length && CancellationToken.is(args[args.length - 1]) ? args.pop() : undefined;
if (cancellationToken && cancellationToken.isCancellationRequested) {
return Promise.reject(this.cancelError());
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the comment above about subbing in a magic string for the cancellation token itself, it looks like we don't pass the state of token - whether it's already been cancelled or not - to the receiving end. If that's the case, then by removing this block, we remove handling the case in which the token has already been cancelled when we get here, since I don't believe that it will fire the onCancellationRequested event again. In that case, should we send the cancellation notice immediately after sending the request itself?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Yes, sending the cancellation notice directly after sending the request sounds reasonable to me.

Copy link
Contributor Author

@tortmayr tortmayr Sep 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@colin-grant-work After investigating and testing this it turns out that both main CancellationToken implementations (Theia and vscode-languageserver) already have a special shortcut event in place that will trigger newly registered cancellation listeners on already canceled tokens immediately. So the cancellation notice for early canceled tokens is already passed correctly to the receiving side.

However, just to be on the safe side (and since in theory also custom cancellation token implementations could be used) I still added the discussed behavior. Directly after sending the request we check whether the token is already canceled. If so, send the cancellation notice, otherwise listen on the onCancellationRequested event.

Ensure that cancelling an RPC call does not result in an automatic rejection on the calling side.
Instead the token is passed to the receiving side and handed there. 
This restores the cancellation strategy that was used with the old json-rpc architecture (prior to 1.28)

Contributed on behalf of STMicroelectronics.
Fixes eclipse-theia#11685
Copy link
Contributor

@colin-grant-work colin-grant-work left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This restores the old behavior: the backend receives the cancellation as expected, and the frontend receives the response generated by the backend in case of cancellation. 👍 Thanks!

@colin-grant-work colin-grant-work merged commit c091f25 into eclipse-theia:master Sep 27, 2022
@colin-grant-work
Copy link
Contributor

@JonasHelming, I have a high level of confidence in this solution, and I believe there's little chance of regression. But I wouldn't insist on its inclusion in the community release if there are objections or concerns.

@colin-grant-work colin-grant-work added this to the 1.30.0 milestone Sep 27, 2022
@JonasHelming
Copy link
Contributor

OK, I talked to Tobi and agree. We do not have a formal process, but @paul-marechal or @tsmaeder would you mind to either give your OK, too or veto?

@tsmaeder
Copy link
Contributor

The solution looks good to me, as for whether to include this in the community release: does the behaviour we fix in this PR cause problems "in the wild" and how bad are those problems? #11685 doesn't really have info about the real world impact. If it has significant impact, let's include it, if it doesn't, it's an automatic "no" from me ;-)

@JonasHelming
Copy link
Contributor

Yes, that is a valid point, @colin-grant-work could you comment on this? I think I remember you mentioned it to be a "corner case"?

@colin-grant-work
Copy link
Contributor

colin-grant-work commented Sep 28, 2022

@JonasHelming, @tsmaeder, the impact on us was non-trivial - a whole widget ended up hanging in an indeterminate state because we hadn't expected the Promise generated by the backend call to ever get rejected - either it would succeed or be canceled with partial return. But it took a number of steps to get there: we had to know we wanted to time out at some point and issue the cancelation but also expect cancellation to work in a fairly timely manner and without rejection. Those assumptions had been correct before, but I'm not sure how many teams will have gotten themselves in the same situation.

@JonasHelming
Copy link
Contributor

@colin-grant-work : Will you pick up the release on Thursday or shortly after? If so, we would have another 2 weeks before we actually anounce the release in case there are any regressions.

@colin-grant-work
Copy link
Contributor

@JonasHelming, since we uplifted to 1.28 and encountered this problem, we've adjusted our code to handle the cancellation rejection on the frontend, so it isn't urgent for us that it make it into the community release, but if there are products waiting to uplift until they can uplift to the community release, then it might still be worth it to get this fix in so that they don't run into the same problem when they do.

@JonasHelming
Copy link
Contributor

Sorry, I rephrase my question: Will you uplift your project to the community release soon? If that is the case, you would most likely identify any potential regressions we find with this fix before we announce the release in two weeks from now. Even if the risk is low, this would be another safety net.

@JonasHelming
Copy link
Contributor

In any case, my vote is a "yes" on this one based on what you described. @paul-marechal ?

@colin-grant-work
Copy link
Contributor

@JonasHelming, I think we will start an uplift to 1.30, yes, so we should catch any regressions in practical code.

@JonasHelming
Copy link
Contributor

OK, we will include this.

martin-fleck-at pushed a commit that referenced this pull request Sep 29, 2022
Ensure that cancelling an RPC call does not result in an automatic rejection
on the calling side. Instead the token is passed to the receiving side and
handled there. This restores the cancellation strategy that was used with the
old json-rpc architecture (prior to 1.28).

Contributed on behalf of STMicroelectronics.
martin-fleck-at pushed a commit that referenced this pull request Sep 29, 2022
Ensure that cancelling an RPC call does not result in an automatic rejection
on the calling side. Instead the token is passed to the receiving side and
handled there. This restores the cancellation strategy that was used with the
old json-rpc architecture (prior to 1.28).

Contributed on behalf of STMicroelectronics.
@tsmaeder
Copy link
Contributor

@colin-grant-work given the real-world impact, I'm fine with the inclusion, as well.

@JonasHelming
Copy link
Contributor

This is now part of the release (1.29.1) Thanks @colin-grant-work for bringing this up!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CommunityReleasePatch1.29 jsonrpc issues related to jsonrpc
Projects
None yet
Development

Successfully merging this pull request may close these issues.

New RPC changes cancellation token behavior
5 participants