Skip to content

Commit df6f97c

Browse files
authored
refactor(rt): add retry logging; rename retry middleware (#528)
1 parent bc49c3b commit df6f97c

File tree

6 files changed

+50
-21
lines changed

6 files changed

+50
-21
lines changed

runtime/protocol/http/common/src/aws/smithy/kotlin/runtime/http/middleware/Md5Checksum.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import aws.smithy.kotlin.runtime.http.HttpBody
1111
import aws.smithy.kotlin.runtime.http.HttpClientFeatureFactory
1212
import aws.smithy.kotlin.runtime.http.operation.SdkHttpOperation
1313
import aws.smithy.kotlin.runtime.http.request.header
14+
import aws.smithy.kotlin.runtime.util.InternalApi
1415
import aws.smithy.kotlin.runtime.util.encodeBase64String
1516
import aws.smithy.kotlin.runtime.util.md5
1617

@@ -20,6 +21,7 @@ import aws.smithy.kotlin.runtime.util.md5
2021
* - https://awslabs.github.io/smithy/1.0/spec/core/behavior-traits.html#httpchecksumrequired-trait
2122
* - https://datatracker.ietf.org/doc/html/rfc1864.html
2223
*/
24+
@InternalApi
2325
class Md5Checksum : Feature {
2426

2527
companion object Feature : HttpClientFeatureFactory<Md5Checksum, Md5Checksum> {
Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,31 +11,67 @@ import aws.smithy.kotlin.runtime.http.HttpBody
1111
import aws.smithy.kotlin.runtime.http.HttpClientFeatureFactory
1212
import aws.smithy.kotlin.runtime.http.operation.SdkHttpOperation
1313
import aws.smithy.kotlin.runtime.http.operation.deepCopy
14+
import aws.smithy.kotlin.runtime.http.operation.getLogger
1415
import aws.smithy.kotlin.runtime.http.request.HttpRequestBuilder
16+
import aws.smithy.kotlin.runtime.logging.Logger
17+
import aws.smithy.kotlin.runtime.retries.RetryDirective
1518
import aws.smithy.kotlin.runtime.retries.RetryPolicy
1619
import aws.smithy.kotlin.runtime.retries.RetryStrategy
20+
import aws.smithy.kotlin.runtime.util.InternalApi
21+
22+
/**
23+
* Retry requests with the given strategy and policy
24+
* @param strategy the [RetryStrategy] to retry failed requests with
25+
* @param policy the [RetryPolicy] used to determine when to retry
26+
*/
27+
@InternalApi
28+
class Retry(
29+
private val strategy: RetryStrategy,
30+
private val policy: RetryPolicy<Any?>
31+
) : Feature {
1732

18-
class RetryFeature(private val strategy: RetryStrategy, private val policy: RetryPolicy<Any?>) : Feature {
1933
class Config {
2034
var strategy: RetryStrategy? = null
2135
var policy: RetryPolicy<Any?>? = null
2236
}
2337

24-
companion object Feature : HttpClientFeatureFactory<Config, RetryFeature> {
25-
override val key: FeatureKey<RetryFeature> = FeatureKey("RetryFeature")
38+
companion object Feature : HttpClientFeatureFactory<Config, Retry> {
39+
override val key: FeatureKey<Retry> = FeatureKey("Retry")
2640

27-
override fun create(block: Config.() -> Unit): RetryFeature {
41+
override fun create(block: Config.() -> Unit): Retry {
2842
val config = Config().apply(block)
2943
val strategy = requireNotNull(config.strategy) { "strategy is required" }
3044
val policy = requireNotNull(config.policy) { "policy is required" }
31-
return RetryFeature(strategy, policy)
45+
return Retry(strategy, policy)
46+
}
47+
}
48+
49+
/**
50+
* Wrapper around [policy] that logs termination decisions
51+
*/
52+
private class PolicyLogger(
53+
private val policy: RetryPolicy<Any?>,
54+
private val logger: Logger,
55+
) : RetryPolicy<Any?> {
56+
override fun evaluate(result: Result<Any?>): RetryDirective = policy.evaluate(result).also {
57+
if (it is RetryDirective.TerminateAndFail) {
58+
logger.debug { "request failed with non-retryable error" }
59+
}
3260
}
3361
}
3462

3563
override fun <I, O> install(operation: SdkHttpOperation<I, O>) {
3664
operation.execution.finalize.intercept { req, next ->
3765
if (req.subject.isRetryable) {
38-
strategy.retry(policy) {
66+
var attempt = 1
67+
val logger = req.context.getLogger("Retry")
68+
val wrappedPolicy = PolicyLogger(policy, logger)
69+
70+
strategy.retry(wrappedPolicy) {
71+
if (attempt > 1) {
72+
logger.debug { "retrying request, attempt $attempt" }
73+
}
74+
3975
// Deep copy the request because later middlewares (e.g., signing) mutate it
4076
val reqCopy = req.deepCopy()
4177

@@ -44,6 +80,8 @@ class RetryFeature(private val strategy: RetryStrategy, private val policy: Retr
4480
is HttpBody.Streaming -> body.reset()
4581
}
4682

83+
attempt++
84+
4785
next.call(reqCopy)
4886
}
4987
} else {

runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/client/SdkLogMode.kt

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,6 @@ sealed class SdkLogMode(private val mask: Int) {
5050
override fun toString(): String = "LogResponseWithBody"
5151
}
5252

53-
/**
54-
* Log retry attempts
55-
*/
56-
object LogRetries : SdkLogMode(0x10) {
57-
override fun toString(): String = "LogRetries"
58-
}
59-
6053
internal class Composite(mask: Int) : SdkLogMode(mask)
6154

6255
operator fun plus(mode: SdkLogMode): SdkLogMode = Composite(mask or mode.mask)
@@ -76,7 +69,6 @@ sealed class SdkLogMode(private val mask: Int) {
7669
LogRequestWithBody,
7770
LogResponse,
7871
LogResponseWithBody,
79-
LogRetries
8072
)
8173
}
8274
override fun toString(): String =

runtime/runtime-core/common/test/aws/smithy/kotlin/runtime/client/SdkLogModeTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class SdkLogModeTest {
3131
fun testToString() {
3232
val mode = SdkLogMode.allModes().reduce { acc, curr -> acc + curr }
3333
assertTrue { SdkLogMode.allModes().all { mode.isEnabled(it) } }
34-
val expected = "SdkLogMode(LogRequest|LogRequestWithBody|LogResponse|LogResponseWithBody|LogRetries)"
34+
val expected = "SdkLogMode(LogRequest|LogRequestWithBody|LogResponse|LogResponseWithBody)"
3535
assertEquals(expected, mode.toString())
3636
}
3737
}

smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/core/RuntimeTypes.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ object RuntimeTypes {
4949
object Middlware {
5050
val Md5ChecksumMiddleware = runtimeSymbol("Md5Checksum", KotlinDependency.HTTP, "middleware")
5151
val MutateHeadersMiddleware = runtimeSymbol("MutateHeaders", KotlinDependency.HTTP, "middleware")
52-
val RetryFeature = runtimeSymbol("RetryFeature", KotlinDependency.HTTP, "middleware")
52+
val Retry = runtimeSymbol("Retry", KotlinDependency.HTTP, "middleware")
5353
val ResolveEndpoint = runtimeSymbol("ResolveEndpoint", KotlinDependency.HTTP, "middleware")
5454
}
5555

smithy-kotlin-codegen/src/main/kotlin/software/amazon/smithy/kotlin/codegen/retries/StandardRetryMiddleware.kt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,11 @@ import software.amazon.smithy.kotlin.codegen.rendering.protocol.HttpFeatureMiddl
1313
* Adds retry wrappers around operation invocations.
1414
*/
1515
class StandardRetryMiddleware : HttpFeatureMiddleware() {
16-
companion object {
17-
const val name: String = "RetryFeature"
18-
}
1916

20-
override val name: String = Companion.name
17+
override val name: String = RuntimeTypes.Http.Middlware.Retry.name
2118

2219
override fun renderConfigure(writer: KotlinWriter) {
23-
writer.addImport(RuntimeTypes.Http.Middlware.RetryFeature)
20+
writer.addImport(RuntimeTypes.Http.Middlware.Retry)
2421
writer.addImport(RuntimeTypes.Core.Retries.Impl.StandardRetryPolicy)
2522

2623
writer.write("strategy = config.retryStrategy")

0 commit comments

Comments
 (0)