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

CodeQL model editor: user should be able to stop modeling before the main editor view is open #3189

Merged
merged 5 commits into from
Jan 5, 2024

Conversation

norascheuch
Copy link
Contributor

@norascheuch norascheuch commented Jan 3, 2024

Opening the model editor takes a while. This PR gives the user the option to cancel the progress and not open the editor.

When cancelling the open process the user effectively cancels a query run. This results in an error message and a telemetry event.
Screenshot 2024-01-04 at 11 53 31

From my investigation I deduct that this behaviour stems from the query server in https://github.com/github/vscode-codeql/blob/nora/make-model-editor-open-cancellable/extensions/ql-vscode/src/query-server/run-queries.ts#L69

I would be happy for feedback on how to resolve this issue.

Checklist

  • CHANGELOG.md has been updated to incorporate all user visible changes made by this pull request.
  • Issues have been created for any UI or other user-facing changes made by this pull request.
  • [Maintainers only] If this pull request makes user-facing changes that require documentation changes, open a corresponding docs pull request in the github/codeql repo and add the ready-for-doc-review label there.

@norascheuch norascheuch marked this pull request as ready for review January 4, 2024 10:58
@norascheuch norascheuch requested review from a team as code owners January 4, 2024 10:58
Copy link
Contributor

@shati-patel shati-patel left a comment

Choose a reason for hiding this comment

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

Thanks! This looks mostly fine to me, just had a poke at the error/telemetry issue you mentioned 🔍

(I wouldn't mind another review though—I'm still not that confident with the model editor code 🙈)

Comment on lines 468 to 469
} catch (err) {
void showAndLogExceptionWithTelemetry(
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the error + telemetry event is coming from here (since we catch the UserCancellationException and treat it like a normal error). Maybe we can check for the type of error here?
Something like:

Suggested change
} catch (err) {
void showAndLogExceptionWithTelemetry(
} catch (err) {
if (err instanceof UserCancellationException) {
this.panel?.dispose();
return;
}
void showAndLogExceptionWithTelemetry(

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree that this is where the log message is coming from, so we have the power to silence it. Annoyingly, the error isn't actually a UserCancellationException :shakes_fist:. As far as I can tell the error is coming from a rpc library and not our code. We may need to add a custom check for this type of error, like if the message matches The request \(.*\) has been cancelled.

Adding in this.panel?.dispose() is also good because otherwise the panel lingers open in the "loading" state and you need to close it manually.

So maybe something like

if (
  getErrorMessage(err).match(/The request \(.*\) has been cancelled/i)
) {
  this.panel?.dispose();
  return;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This looks really good! Yes, the catch is catching this error, I was just not sure if there are other instances where we might get a The request \(.*\) has been cancelled that was not due to a user cancellation...

Copy link
Contributor

Choose a reason for hiding this comment

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

Annoyingly, the error isn't actually a UserCancellationException

Is it not? 😅 That if snippet worked when I tested locally (though maybe I didn't test all cases 🤔)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The if works, but it could be imaginable that something went wrong internally when running the query and an error message with the same text is produced, but we now swallow it.

Copy link
Contributor

Choose a reason for hiding this comment

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

That if snippet worked when I tested locally

It didn't work for me 🤔 . I also tried adding a breakpoint there so I could poke at the error manually. I'm very happy to try again if you disagree.

it could be imaginable that something went wrong internally when running the query and an error message with the same text is produced, but we now swallow it.

Maybe but I'd expect the message wouldn't say "cancelled" then. How about we still log it but not show the popup? Keeping telemetry could be nice so we know how many people are cancelling this. We could do something like

const error = redactableError(
asError(e),
)`Failed to prompt for GitHub repository download`;
void this.app.logger.log(error.fullMessageWithStack);
this.app.telemetry?.sendError(error);

Copy link
Contributor

Choose a reason for hiding this comment

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

The if works, but it could be imaginable that something went wrong internally when running the query and an error message with the same text is produced, but we now swallow it.

Sorry, I meant that my original suggestion of if (err instanceof UserCancellationException) worked fine for me! I was wondering what Robert meant by saying the error wasn't a UserCancellationException 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ah! It depends on when you press the cancel button! There are two progress windows and for the first everything works, for the second it doesn't. So after the dependencies are installed and the query is actually run, we need the text match.

Copy link
Member

Choose a reason for hiding this comment

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

Something which might be less hacky is the following, which checks the type of the other error and that it is a cancellation error:

import { ResponseError } from "vscode-jsonrpc";
import { LSPErrorCodes } from "vscode-languageclient";

// ...

      if (
        err instanceof ResponseError &&
        err.code === LSPErrorCodes.RequestCancelled
      ) {
        this.panel?.dispose();
        return;
      }

Copy link
Contributor

@robertbrignull robertbrignull left a comment

Choose a reason for hiding this comment

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

Code LGTM (apart from the point that @shati-patel mentioned).

What you've done (i.e. checking the token in between each expensive operation) is exactly the right thing to do.

Comment on lines 468 to 469
} catch (err) {
void showAndLogExceptionWithTelemetry(
Copy link
Contributor

Choose a reason for hiding this comment

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

I agree that this is where the log message is coming from, so we have the power to silence it. Annoyingly, the error isn't actually a UserCancellationException :shakes_fist:. As far as I can tell the error is coming from a rpc library and not our code. We may need to add a custom check for this type of error, like if the message matches The request \(.*\) has been cancelled.

Adding in this.panel?.dispose() is also good because otherwise the panel lingers open in the "loading" state and you need to close it manually.

So maybe something like

if (
  getErrorMessage(err).match(/The request \(.*\) has been cancelled/i)
) {
  this.panel?.dispose();
  return;
}

@norascheuch
Copy link
Contributor Author

If we're confident no other non-user triggered The request \(.*\) has been cancelled error message can occur this should be good to go.

Copy link
Contributor

@robertbrignull robertbrignull left a comment

Choose a reason for hiding this comment

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

🎉

@norascheuch norascheuch enabled auto-merge January 5, 2024 12:44
@norascheuch norascheuch merged commit 1d42d48 into main Jan 5, 2024
14 checks passed
@norascheuch norascheuch deleted the nora/make-model-editor-open-cancellable branch January 5, 2024 12:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants