Skip to content

Commit 25e244c

Browse files
committed
implement backoff logic to promptReauth
1 parent e121827 commit 25e244c

File tree

1 file changed

+56
-18
lines changed
  • plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/util

1 file changed

+56
-18
lines changed

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/util/CodeWhispererUtil.kt

Lines changed: 56 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,16 @@ import com.intellij.openapi.vfs.VirtualFile
1616
import com.intellij.openapi.wm.WindowManager
1717
import com.intellij.ui.ComponentUtil
1818
import kotlinx.coroutines.CoroutineScope
19+
import kotlinx.coroutines.Dispatchers
1920
import kotlinx.coroutines.Job
2021
import kotlinx.coroutines.delay
2122
import kotlinx.coroutines.launch
2223
import kotlinx.coroutines.yield
24+
import kotlinx.coroutines.delay
25+
import kotlinx.coroutines.runBlocking
26+
import kotlinx.coroutines.withContext
27+
import kotlin.math.min
28+
import software.amazon.awssdk.core.exception.SdkClientException
2329
import software.amazon.awssdk.services.codewhispererruntime.model.Completion
2430
import software.amazon.awssdk.services.codewhispererruntime.model.OptOutPreference
2531
import software.aws.toolkits.core.utils.getLogger
@@ -47,6 +53,7 @@ import software.aws.toolkits.jetbrains.utils.isQExpired
4753
import software.aws.toolkits.jetbrains.utils.notifyError
4854
import software.aws.toolkits.jetbrains.utils.notifyInfo
4955
import software.aws.toolkits.jetbrains.utils.pluginAwareExecuteOnPooledThread
56+
import software.aws.toolkits.jetbrains.utils.runUnderProgressIfNeeded
5057
import software.aws.toolkits.resources.message
5158
import software.aws.toolkits.telemetry.CodewhispererCompletionType
5259
import software.aws.toolkits.telemetry.CodewhispererGettingStartedTask
@@ -137,6 +144,9 @@ fun VirtualFile.toCodeChunk(path: String): Sequence<Chunk> = sequence {
137144
}
138145

139146
object CodeWhispererUtil {
147+
private const val MAX_RETRY_DELAY_MS = 300000 // 5 minutes in milliseconds
148+
private const val INITIAL_RETRY_DELAY_MS = 1000 // 1 second
149+
140150
fun getCompletionType(completion: Completion): CodewhispererCompletionType {
141151
val content = completion.content()
142152
val nonBlankLines = content.split("\n").count { it.isNotBlank() }
@@ -161,32 +171,60 @@ object CodeWhispererUtil {
161171
}
162172

163173
// This will be called only when there's a CW connection, but it has expired(either accessToken or refreshToken)
164-
// 1. If connection is expired, try to refresh
165-
// 2. If not able to refresh, requesting re-login by showing a notification
166-
// 3. The notification will be shown
167-
// 3.1 At most once per IDE restarts.
168-
// 3.2 At most once after IDE restarts,
169-
// for example, when user performs security scan or fetch code completion for the first time
170-
// Return true if need to re-auth, false otherwise
174+
// 1. Attempt to refresh the connection
175+
// 2. If refresh fails due to network issues (SdkClientException), it will:
176+
// 2.1 Retry the refresh with exponential backoff
177+
// 2.2 Continue retrying indefinitely until successful or a non-network error occurs
178+
// 3. If refresh is successful at any point, it will:
179+
// 3.1 Show a re-authentication prompt if it hasn't been shown yet in this IDE session
180+
// 3.2 Mark the re-auth prompt as shown (if not during plugin startup)
181+
// 3.3 Notify about session configuration if not using Sono
182+
// 4. If a non-network error occurs (not SdkClientException), it will stop retrying and return true
183+
// - Returns false if re-authentication was successful (no further action needed)
184+
// - Returns true if re-authentication failed and manual re-auth is required
171185
fun promptReAuth(project: Project, isPluginStarting: Boolean = false): Boolean {
186+
// Check if re-authentication is needed
172187
if (!isQExpired(project)) return false
173188
val tokenProvider = tokenProvider(project) ?: return false
189+
174190
return try {
175-
maybeReauthProviderIfNeeded(project, ReauthSource.CODEWHISPERER, tokenProvider) {
176-
runInEdt {
177-
if (!CodeWhispererService.hasReAuthPromptBeenShown()) {
178-
notifyConnectionExpiredRequestReauth(project)
179-
}
180-
if (!isPluginStarting) {
181-
CodeWhispererService.markReAuthPromptShown()
182-
}
183-
if (!tokenConnection(project).isSono()) {
184-
notifySessionConfiguration(project)
191+
runUnderProgressIfNeeded(project, "Refreshing Connection", true) {
192+
var currentDelay = INITIAL_RETRY_DELAY_MS.toLong()
193+
var attempt = 1
194+
195+
while (true) {
196+
try {
197+
// Attempt to re-authenticate
198+
val result = maybeReauthProviderIfNeeded(project, ReauthSource.CODEWHISPERER, tokenProvider) {
199+
runInEdt {
200+
// Show re-auth prompt if it hasn't been shown yet
201+
if (!CodeWhispererService.hasReAuthPromptBeenShown()) {
202+
notifyConnectionExpiredRequestReauth(project)
203+
}
204+
// Mark re-auth prompt as shown if not during plugin startup
205+
if (!isPluginStarting) {
206+
CodeWhispererService.markReAuthPromptShown()
207+
}
208+
// Notify about session configuration if not using Sono
209+
if (!tokenConnection(project).isSono()) {
210+
notifySessionConfiguration(project)
211+
}
212+
}
213+
}
214+
return@runUnderProgressIfNeeded !result // Assuming maybeReauthProviderIfNeeded returns true if reauth is needed
215+
} catch (e: SdkClientException) {
216+
getLogger<CodeWhispererService>().warn(e) { "Attempt $attempt failed. Retrying in $currentDelay ms" }
217+
Thread.sleep(currentDelay)
218+
currentDelay = minOf(MAX_RETRY_DELAY_MS.toLong(), (currentDelay * 2).toLong())
219+
attempt++
185220
}
186221
}
222+
// This line should never be reached due to the infinite loop, but it's needed to satisfy the compiler
223+
false
187224
}
188225
} catch (e: Exception) {
189-
getLogger<CodeWhispererService>().warn(e) { "prompt reauth failed with unexpected error" }
226+
// Log any unexpected errors and return true to indicate re-auth is needed
227+
getLogger<CodeWhispererService>().warn(e) { "Prompt reauth failed with unexpected error" }
190228
true
191229
}
192230
}

0 commit comments

Comments
 (0)