Skip to content

fix(amazonq): increase frequency of bearer token sync to server #5636

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

Merged
merged 5 commits into from
May 12, 2025

Conversation

samgst-amazon
Copy link
Contributor

Problem: We are seeing high error rate of ListWorkspaceMetadata ( called by Flare) due to expired bearer tokens in Flare in JetBrains(high chance). This is because the current bearer token sync from IDE to Flare is not robust. In VS Code, we sync bearer token per 10 seconds, in JB, we sync whenever JB bearer token changes. There are edge cases when new fresh bearer token is not up to date in Flare.

Short term solution: In JetBrains, automatically sync bearer token to Flare per 10 seconds or a shorter interval.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)

Description

Checklist

  • My code follows the code style of this project
  • I have added tests to cover my changes
  • A short description of the change has been added to the CHANGELOG if the change is customer-facing in the IDE.
  • I have added metrics for my changes (if required)

License

I confirm that my contribution is made under the terms of the Apache 2.0 license.

@samgst-amazon samgst-amazon requested a review from a team as a code owner April 24, 2025 23:40
tokenSyncTask = scheduler.scheduleWithFixedDelay(
{
try {
if (isQConnected(project) && !isQExpired(project)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

isQExpired

fun isQExpired(project: Project): Boolean {
val manager = ToolkitConnectionManager.getInstance(project)
val qState = manager.connectionStateForFeature(QConnection.getInstance())
val cwState = manager.connectionStateForFeature(CodeWhispererConnection.getInstance())
LOG.debug {
"qConnectionState: $qState; cwConnectionState: $cwState"
}
return qState == BearerTokenAuthState.NEEDS_REFRESH || cwState == BearerTokenAuthState.NEEDS_REFRESH
}

make sure JB itself can automatically switch from NEEDS_REFRESH status to other status.. otherwise if JB stuck in NEEDS_REFRESH, this won't sync

Copy link
Contributor

Choose a reason for hiding this comment

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

Otherwise, this PR looks good

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What do you mean by this? Isn't refresh logic handled by calls to reauthConnectionIfNeeded everywhere? If the IDE idles out and the token is no longer syncing because it needs to be refreshed, isn't that expected? We could add something to try and refresh the token here when it's expired, but I think that would increase the frequency of asking users to reauth.

I'm just a little confused about what AI you're implying here.

Copy link
Contributor

@leigaol leigaol Apr 25, 2025

Choose a reason for hiding this comment

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

What I meant is: You'd double check if this NEEDS_REFRESH is referring to the automatic bearer token refresh that can be done by the JB IDE itself (calling the getToken API) or it is something that requires a full re-auth which requires user input.

Copy link
Contributor

@leigaol leigaol Apr 25, 2025

Choose a reason for hiding this comment

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

See this code:

When the bearerToken is in the NEEDS_REFRESH state, it can go through tokenProvider.resolveToken() and actually starts to have a new valid bearer token. This is done as long as the user login is valid for about 3 months.

The flow I want to verify is:
Time 0:00: User login, gets a fresh bearer token.
Time 1:00: bearer token expires, BearerTokenAuthState becomes NEEDS_REFRESH state
From 1:00, per 10 seconds, the BearerTokenAuthState should automatically switch from NEEDS_REFRESH state to AUTHORIZED by going through tokenProvider.resolveToken(), even though user does not use the JetBrains IDE. Such that in your PR, the isQExpired can return false and new bearer token can keep being pushed to the Flare.

Otherwise, from time 1:00, BearerTokenAuthState becomes NEEDS_REFRESH state, isQExpired returns true, then no new bearer token will be pushed to Flare, and Flare will make API calls with 4xx.

TLDR: Does this PR work for the case when user login and after one hour of IDE idle (first bearer token expires), Flare can still get the new refresh bearer token and use it to call API?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you. I added some more logic to my implementation to try and address this.

Copy link

github-actions bot commented Apr 25, 2025

Qodana Community for JVM

It seems all right 👌

No new problems were found according to the checks applied

💡 Qodana analysis was run in the pull request mode: only the changed files were checked
☁️ View the detailed Qodana report

Contact Qodana team

Contact us at qodana-support@jetbrains.com

@samgst-amazon samgst-amazon merged commit 1d79d77 into main May 12, 2025
14 of 16 checks passed
@samgst-amazon samgst-amazon deleted the samgst/q-lsp-token-refresh-periodic branch May 12, 2025 18:41
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.

3 participants