Skip to content

Commit 44b32f3

Browse files
committed
Moving RetryableOperation to separate class.
1 parent ab927ba commit 44b32f3

File tree

3 files changed

+55
-61
lines changed

3 files changed

+55
-61
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import software.amazon.awssdk.utils.IoUtils
2020
import software.aws.toolkits.core.utils.debug
2121
import software.aws.toolkits.core.utils.getLogger
2222
import software.aws.toolkits.jetbrains.core.AwsClientManager
23-
import software.aws.toolkits.jetbrains.services.amazonq.clients.RetryableOperation
23+
import software.aws.toolkits.jetbrains.services.amazonq.RetryableOperation
2424
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.CodeWhispererCodeScanSession.Companion.APPLICATION_ZIP
2525
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.CodeWhispererCodeScanSession.Companion.AWS_KMS
2626
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.CodeWhispererCodeScanSession.Companion.CONTENT_MD5
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package software.aws.toolkits.jetbrains.services.amazonq
5+
6+
import kotlinx.coroutines.delay
7+
import kotlinx.coroutines.runBlocking
8+
import software.amazon.awssdk.core.exception.RetryableException
9+
import kotlin.random.Random
10+
11+
class RetryableOperation<T> {
12+
private var attempts = 0
13+
private var currentDelay = INITIAL_DELAY
14+
15+
private fun getJitteredDelay(): Long {
16+
currentDelay = (currentDelay * 2).coerceAtMost(MAX_BACKOFF)
17+
return (currentDelay * (0.5 + Random.nextDouble(0.5))).toLong()
18+
}
19+
20+
fun execute(
21+
operation: () -> T,
22+
isRetryable: (Exception) -> Boolean = { it is RetryableException },
23+
errorHandler: ((Exception, Int) -> Nothing),
24+
): T = runBlocking {
25+
executeSuspend(operation, isRetryable, errorHandler)
26+
}
27+
28+
suspend fun executeSuspend(
29+
operation: suspend () -> T,
30+
isRetryable: (Exception) -> Boolean = { it is RetryableException },
31+
errorHandler: (suspend (Exception, Int) -> Nothing),
32+
): T {
33+
while (attempts < MAX_RETRY_ATTEMPTS) {
34+
try {
35+
return operation()
36+
} catch (e: Exception) {
37+
attempts++
38+
if (attempts >= MAX_RETRY_ATTEMPTS || !isRetryable(e)) {
39+
errorHandler.invoke(e, attempts)
40+
}
41+
delay(getJitteredDelay())
42+
}
43+
}
44+
45+
throw RuntimeException("Unexpected state after $attempts attempts")
46+
}
47+
48+
companion object {
49+
private const val INITIAL_DELAY = 100L
50+
private const val MAX_BACKOFF = 10000L
51+
private const val MAX_RETRY_ATTEMPTS = 3
52+
}
53+
}

plugins/amazonq/shared/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/clients/AmazonQStreamingClient.kt

Lines changed: 1 addition & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@ package software.aws.toolkits.jetbrains.services.amazonq.clients
66
import com.intellij.openapi.components.Service
77
import com.intellij.openapi.components.service
88
import com.intellij.openapi.project.Project
9-
import kotlinx.coroutines.delay
109
import kotlinx.coroutines.future.await
11-
import software.amazon.awssdk.core.exception.RetryableException
1210
import software.amazon.awssdk.core.exception.SdkException
1311
import software.amazon.awssdk.services.codewhispererstreaming.CodeWhispererStreamingAsyncClient
1412
import software.amazon.awssdk.services.codewhispererstreaming.model.ExportContext
@@ -21,11 +19,11 @@ import software.aws.toolkits.core.utils.warn
2119
import software.aws.toolkits.jetbrains.core.awsClient
2220
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
2321
import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
22+
import software.aws.toolkits.jetbrains.services.amazonq.RetryableOperation
2423
import java.time.Instant
2524
import java.util.concurrent.TimeoutException
2625
import java.util.concurrent.atomic.AtomicReference
2726
import javax.naming.ServiceUnavailableException
28-
import kotlin.random.Random
2927

3028
@Service(Service.Level.PROJECT)
3129
class AmazonQStreamingClient(private val project: Project) {
@@ -115,60 +113,3 @@ class AmazonQStreamingClient(private val project: Project) {
115113
fun getInstance(project: Project) = project.service<AmazonQStreamingClient>()
116114
}
117115
}
118-
119-
class RetryableOperation<T> {
120-
private var attempts = 0
121-
private var currentDelay = INITIAL_DELAY
122-
123-
private fun getJitteredDelay(): Long {
124-
currentDelay = (currentDelay * 2).coerceAtMost(MAX_BACKOFF)
125-
return (currentDelay * (0.5 + Random.nextDouble(0.5))).toLong()
126-
}
127-
128-
fun execute(
129-
operation: () -> T,
130-
isRetryable: (Exception) -> Boolean = { it is RetryableException },
131-
errorHandler: ((Exception, Int) -> Nothing)? = null,
132-
): T {
133-
while (attempts < MAX_RETRY_ATTEMPTS) {
134-
try {
135-
return operation()
136-
} catch (e: Exception) {
137-
attempts++
138-
if (attempts >= MAX_RETRY_ATTEMPTS || !isRetryable(e)) {
139-
errorHandler?.invoke(e, attempts) ?: throw e
140-
}
141-
142-
Thread.sleep(getJitteredDelay())
143-
}
144-
}
145-
146-
throw RuntimeException("Unexpected state after $attempts attempts")
147-
}
148-
149-
suspend fun executeSuspend(
150-
operation: suspend () -> T,
151-
isRetryable: (Exception) -> Boolean = { it is RetryableException },
152-
errorHandler: (suspend (Exception, Int) -> Nothing)? = null,
153-
): T {
154-
while (attempts < MAX_RETRY_ATTEMPTS) {
155-
try {
156-
return operation()
157-
} catch (e: Exception) {
158-
attempts++
159-
if (attempts >= MAX_RETRY_ATTEMPTS || !isRetryable(e)) {
160-
errorHandler?.invoke(e, attempts) ?: throw e
161-
}
162-
delay(getJitteredDelay())
163-
}
164-
}
165-
166-
throw RuntimeException("Unexpected state after $attempts attempts")
167-
}
168-
169-
companion object {
170-
private const val INITIAL_DELAY = 100L
171-
private const val MAX_BACKOFF = 10000L
172-
private const val MAX_RETRY_ATTEMPTS = 3
173-
}
174-
}

0 commit comments

Comments
 (0)