awslabs / aws-sdk-swift

Apache License 2.0
377 stars 74 forks source link

CRT HTTP client does not timeout when it should #1349

Closed sichanyoo closed 5 months ago

sichanyoo commented 7 months ago

Describe the bug

With the HttpClientConfiguration's connectTimeOut setting set to a short duration (e.g., 1 second), the CRT HTTP client must time out when the server does not send a response. Instead, it stalls, waiting for the response that will never come. This behavior was detected by running localhost:3000 server that simulates an AWS service (DynamoDB in this instance) and sending it a request with HTTP protocol.

Expected Behavior

CRT HTTP client should cut the connection when server does not respond beyond the timeout configuration setting on HttpClientConfiguration.

Current Behavior

CRT HTTP client does not cut the connection, and the connection stalls with no end.

Reproduction Steps

1.. Ask @sichanyoo for the script that simulates AWS service servers.

  1. If running on mac, ensure CRT client is used instead of URL session client by commenting out mac os from this line of code. 3.. Run the script with ./aarch64-apple-darwin-retry-diagnostics --service dynamodb. This will start up the localhost server listening on port 3000.
  2. Then, copy-paste the CLITool code below and run the CLITool.
    func run() async throws {
    let config = try DynamoDBClient.DynamoDBClientConfiguration(
        region: "us-west-2",
        endpoint: "http://localhost:3000",
        retryMode: AWSRetryMode.adaptive,
        httpClientConfiguration: HttpClientConfiguration(connectTimeout: 1, protocolType: .http)
    )
    let client = DynamoDBClient(config: config)
    var id = 0
    while true {
        do {
            _ = try await client.getItem(input: GetItemInput(
                key: ["k": .n("\(id)")],
                tableName: "ignored"
            ))
            print("Request finished. Starting request \(id)")
        } catch {
            print("Encountered an error: \(error)")
        }
        id = id + 1
    }
    }
  3. The terminal running the server will show a progress bar that shows how each scenario is running. But when it gets to the last scenario "timeout" where the simulated server does not send a response to the client ever, it will stall forever in that state instead of server detecting the client-side connection cutoff that triggers the script to finish and print results.
  4. Terminate the CLITool program and the local server via ctrl+C.

Possible Solution

No response

Additional Information/Context

No response

AWS SWIFT SDK version used

0.35.0

Compiler and Version used

Xcode 15.1

Operating System and version

MacOS Sonoma 14.3

sichanyoo commented 6 months ago

Update:

The connetTimeout config exposed in SDK via HttpClientConfiguration is used for connection timeout by the CRT runtime library. Currently there is no configuration exposed in SDK that allows any other timeout (e.g., socket timeout). HttpMonitoringOptions and timeToFirstByte configs in CRT would allow this, which first need to be bound to swift and exposed by aws-crt-swift.

sichanyoo commented 6 months ago

PR linked above depends on below perequisites:

Prerequisite

jbelkins commented 5 months ago

Shipped in AWS SDK for Swift 0.40.0