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

feat!: Create retry modules #710

Merged
merged 29 commits into from
May 24, 2024
Merged

feat!: Create retry modules #710

merged 29 commits into from
May 24, 2024

Conversation

jbelkins
Copy link
Contributor

@jbelkins jbelkins commented May 3, 2024

Issue #

awslabs/aws-sdk-swift#1386

Description of changes

  • Modularize retries per Smithy reference architecture.
  • SmithyRetriesAPI module created with retry-related protocols and data types
  • SmithyRetries module created with default implementations for retry-related types
  • WeatherSDK generated code updated to use modular retry

Scope

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

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

.testTarget(
name: "SmithyRetriesTests",
dependencies: ["ClientRuntime", "SmithyRetriesAPI", "SmithyRetries"]
),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Create Swift targets for SmithyRetriesAPI and SmithyRetries (these are both defined in SRA).

SmithyRetriesAPI has no tests because it consists only of interfaces & types intended solely for holding data, such as configuration types.

- Tests/SmithyXMLTests/*
- Tests/SmithyTimestampsTests/*
- Tests/WeatherSDKTests/*
- Tests/*
Copy link
Contributor Author

Choose a reason for hiding this comment

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

No need to list these test exceptions to lint rules 1 by 1

@@ -5,6 +5,8 @@
// SPDX-License-Identifier: Apache-2.0
//

import struct SmithyRetriesAPI.RetryStrategyOptions

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Separate imports have to be added in many files for the retry types extracted into modules.
I won't comment in these files every time those are added.

static var defaultRetryStrategyOptions: RetryStrategyOptions { RetryStrategyOptions() }
static var defaultRetryStrategyOptions: RetryStrategyOptions {
RetryStrategyOptions(backoffStrategy: ExponentialBackoffStrategy())
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since RetryStrategyOptions (in SmithyRetriesAPI) has been split from ExponentialBackoffStrategy (an implementation in SmithyRetries) the backoff strategy must be provided to the retry strategy options when it is created by the caller.

enum RetryError: Error {
case maxAttemptsReached
case insufficientQuota
}
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 error was made public and moved to its own file in SmithyRetriesAPI.

import enum SmithyRetriesAPI.RetryErrorType
import AwsCommonRuntimeKit

public extension RetryErrorType {
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 extension was split from the declaration of RetryErrorType, which was placed in SmithyRetriesAPI.

This extension goes into the implementation module SmithyRetries since it is dependent on CRT.

public enum RetryError: Error {
case maxAttemptsReached
case insufficientQuota
}
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 type was originally declared along with the DefaultRetryStrategy and was internal.

Now, it's public and in the SmithyRetriesAPI module.

Copy link
Contributor

Choose a reason for hiding this comment

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

Is this actually used by/part of SmithyRetriesAPI? I don't see mention of the 'quota' concept anywhere in API, but it is here (unless I've missed something). I also don't see it used anywhere, presumably its meant to be the type of error that could be thrown by refreshTokenForRetry?

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, might be a good time to add some more swift docs on what each of these types are, what they do, etc. (in general, not just for RetryError). Like RetryErrorInfo, RetryErrorType, RetryStrategy.

case .clientError: return .clientError
}
}
}
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 CRT-dependent extension was split off to its own file in SmithyRetries (see above.)

@@ -50,7 +50,7 @@ public struct RetryStrategyOptions {
/// - availableCapacity: The number of available tokens in a retry quota. Defaults to 500.
/// - maxCapacity: The max number of tokens in a retry quota. Defaults to 500.
public init(
backoffStrategy: RetryBackoffStrategy = ExponentialBackoffStrategy(),
backoffStrategy: RetryBackoffStrategy,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

ExponentialBackoffStrategy was moved off to the implementation module, so this default value can't be set anymore - backoff strategy must be passed in when RetryStrategyOptions is created.

@@ -3,7 +3,7 @@
import ClientRuntime

extension WeatherClientTypes {
public struct Baz: Swift.Equatable {
public struct Baz {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not commenting on individual WeatherSDK files.

Some of the changes seen in WeatherSDK generated code are from features prior to this PR.

@@ -8,6 +8,8 @@
import XCTest

@testable import ClientRuntime
import SmithyRetriesAPI
import SmithyRetries

class OrchestratorTests: XCTestCase {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just a few changes related to the relocation of retry types.

@@ -120,8 +120,6 @@ object ClientRuntimeTypes {
val SDKLogLevel = runtimeSymbol("SDKLogLevel")
val ClientLogMode = runtimeSymbol("ClientLogMode")
val IdempotencyTokenGenerator = runtimeSymbol("IdempotencyTokenGenerator")
val DefaultRetryStrategy = runtimeSymbol("DefaultRetryStrategy")
val RetryStrategyOptions = runtimeSymbol("RetryStrategyOptions")
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Symbols moved to a separate file for retry module types

"https://github.com/smithy-lang/smithy-swift",
Resources.computeAbsolutePath("smithy-swift", "", "SMITHY_SWIFT_CI_DIR"),
"smithy-swift"
),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Our two new modules defined as Swift dependencies

@@ -124,6 +124,7 @@ open class HttpProtocolServiceClient(
val properties: List<ConfigProperty> = ctx.integrations
.flatMap { it.clientConfigurations(ctx).flatMap { it.getProperties(ctx) } }
.let { overrideConfigProperties(it) }
properties.forEach { writer.addImport(it.type) }
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Making sure imports are added as needed

@@ -7,35 +7,7 @@ class ContentMd5MiddlewareTests {
val context = setupTests("Isolated/contentmd5checksum.smithy", "aws.protocoltests.restxml#RestXml")
val contents = getFileContents(context.manifest, "/RestXml/RestXmlProtocolClient.swift")
val expectedContents = """
public func idempotencyTokenWithStructure(input: IdempotencyTokenWithStructureInput) async throws -> IdempotencyTokenWithStructureOutput {
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 test is ridiculously overbroad for "generates ContentMD5 middleware" so I cut out the expected Swift code unrelated to that test assertion.

import software.amazon.smithy.swift.codegen.SwiftWriter
import software.amazon.smithy.swift.codegen.integration.ProtocolGenerator
import software.amazon.smithy.swift.codegen.integration.middlewares.handlers.MiddlewareShapeUtils
import software.amazon.smithy.swift.codegen.middleware.MiddlewarePosition
import software.amazon.smithy.swift.codegen.middleware.MiddlewareRenderable
import software.amazon.smithy.swift.codegen.middleware.MiddlewareStep
import software.amazon.smithy.swift.codegen.swiftmodules.SmithyRetriesTypes

class RetryMiddleware(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Adjust imports and a little code cleanup.

@@ -6,34 +6,7 @@ class IdempotencyTokenTraitTests {
val context = setupTests("Isolated/idempotencyToken.smithy", "aws.protocoltests.restxml#RestXml")
val contents = getFileContents(context.manifest, "/RestXml/RestXmlProtocolClient.swift")
val expectedContents = """
public func idempotencyTokenWithStructure(input: IdempotencyTokenWithStructureInput) async throws -> IdempotencyTokenWithStructureOutput {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Like the test above, the expectation is way way broader than "generates idempotent middleware".

@jbelkins jbelkins marked this pull request as ready for review May 9, 2024 19:42
@jbelkins jbelkins requested review from sichanyoo and dayaffe May 9, 2024 19:42
public enum RetryError: Error {
case maxAttemptsReached
case insufficientQuota
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this actually used by/part of SmithyRetriesAPI? I don't see mention of the 'quota' concept anywhere in API, but it is here (unless I've missed something). I also don't see it used anywhere, presumably its meant to be the type of error that could be thrown by refreshTokenForRetry?

public enum RetryError: Error {
case maxAttemptsReached
case insufficientQuota
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Also, might be a good time to add some more swift docs on what each of these types are, what they do, etc. (in general, not just for RetryError). Like RetryErrorInfo, RetryErrorType, RetryStrategy.

Copy link
Contributor

Choose a reason for hiding this comment

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

Probably would add a lot of noise to this PR, but in the future maybe we consider moving ClientRuntimeTypes into swiftmodules

Copy link
Contributor Author

Choose a reason for hiding this comment

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

True. I have many more of these modularization PRs to tackle, I can do it in a future one.

@jbelkins
Copy link
Contributor Author

@milesziemer

Is this actually used by/part of SmithyRetriesAPI? I don't see mention of the 'quota' concept anywhere in API, but it is here (unless I've missed something). I also don't see it used anywhere, presumably its meant to be the type of error that could be thrown by refreshTokenForRetry?

Agreed. .maxAttemptsReached is implied by the retry configuration in SmithyRetriesAPI so it should stay here, but the . insufficientQuota error is really tied to the "adaptive" implementation. I'll move that error back in with the default implementation.

Also no matter where these go, if these errors are public they should have doc comments. I'll add them.

@jbelkins
Copy link
Contributor Author

jbelkins commented May 14, 2024

@milesziemer Per discussion above:

  • The general-case max retries error was split from the adaptive-related quota error, and the quota error was relocated to SmithyRetries with the retry strategy implementation
  • Doc comments were added to both errors

(Also: fixed a couple unrelated build warnings)

Please re-review.

@jbelkins jbelkins merged commit fdc7a1b into main May 24, 2024
17 checks passed
@jbelkins jbelkins deleted the jbe/modular_retries branch May 24, 2024 17:48
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.

2 participants