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

fix: Make HttpResponse.statusCode getter & setter thread-safe #656

Merged
merged 2 commits into from
May 29, 2024

Conversation

sichanyoo
Copy link
Contributor

@sichanyoo sichanyoo commented Jan 30, 2024

Issue #

awslabs/aws-sdk-swift#1324
aws-amplify/amplify-swift#3708

Addresses SIM ticket /V1219649867.

Description of changes

A customer raised a SIM ticket with the following screenshot of data race warning on IDE:

image

To address this data race warning, use serial queue and hidden property _statusCode to make getter & setter thread-safe. Observed that the thread sanitization warning goes away when running CRT HTTP client with this change.

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.

@jbelkins jbelkins self-requested a review January 30, 2024 00:17
Copy link
Contributor

@jbelkins jbelkins left a comment

Choose a reason for hiding this comment

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

Two things:

  • It is not enough to just do the writes on the serial queue. Writing on the serial queue ensures that writes will not happen at the same time, but does not guarantee that reads will not happen at the same time as writes. To fully ensure no simultaneous access, reads would have to be performed on the queue as well.
  • You create the serial queue as a local variable each time that the private function safelySetStatusCode is called. That means that every write to status code will happen on its own queue, and nothing will actually be deconflicted. To ensure that all writes go onto the same queue, the queue should be a property of either the request or the client engine.

@sichanyoo sichanyoo changed the title Adds serial queue to set status code of HTTP response in thread-safe manner. Make HTTP response an actor to make its properties thread-safe. Jan 30, 2024
@sichanyoo sichanyoo changed the title Make HTTP response an actor to make its properties thread-safe. fix!: Make HTTP response an actor to make its properties thread-safe. Jan 30, 2024
@sichanyoo sichanyoo changed the title fix!: Make HTTP response an actor to make its properties thread-safe. fix!: Make HttpResponse an actor to make its properties thread-safe. Jan 30, 2024
@sichanyoo sichanyoo requested a review from jbelkins February 2, 2024 17:10
Copy link
Contributor

@jbelkins jbelkins left a comment

Choose a reason for hiding this comment

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

A couple questions inline. Most of PR is good - just adding await where needed

Copy link
Contributor

@jbelkins jbelkins left a comment

Choose a reason for hiding this comment

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

See my suggestion on a more efficient way to resume execution when status code changes to a final value

@sichanyoo sichanyoo requested a review from jbelkins February 7, 2024 19:41
Copy link
Contributor

@jbelkins jbelkins left a comment

Choose a reason for hiding this comment

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

See comments. Also, remember that when a continuation is used, whether the result is success or failure, it must be resumed exactly once.

So make sure that every possible path that this request could take (success, failure, cancellation before completion, etc.) results in the continuation being called. As-is, I don't see any resumption of the continuation except on the success path.

Sources/ClientRuntime/Networking/Http/HttpResponse.swift Outdated Show resolved Hide resolved
Sources/ClientRuntime/Networking/Http/HttpResponse.swift Outdated Show resolved Hide resolved
@sichanyoo sichanyoo requested a review from jbelkins February 9, 2024 19:08
@sichanyoo
Copy link
Contributor Author

sichanyoo commented Feb 9, 2024

@jbelkins RE: making sure continuation gets resumed exactly once for all code paths:

For any situation where HTTP response is returned from the server (with any status code >= 200), it's resumed exactly once.

And for any situation that involves a non-HTTP error such as the connection being dropped due to a connection error, those errors are caught by the RetryMiddleware, which is then thrown back to the user without the code execution progressing into DeserializeMiddleware (so the continuation doesn't even get instantiated).

@sichanyoo
Copy link
Contributor Author

From offline discussion: The PRs for this ticket (partner PR: awslabs/aws-sdk-swift#1323) will be put on-hold until deeper investigation is done & it's confirmed all continuation code paths call resume() exactly once.

Also discussed: refactoring CRT HTTP client wrapper in SDK side might be a good follow-up task to this.

@sichanyoo sichanyoo force-pushed the fix/remove-data-race branch from ce1150e to e6b388b Compare May 29, 2024 00:17
@sichanyoo sichanyoo changed the title fix!: Make HttpResponse an actor to make its properties thread-safe. fix!: Make HttpResponse.statusCode getter & setter thread-safe. May 29, 2024
@sichanyoo sichanyoo changed the title fix!: Make HttpResponse.statusCode getter & setter thread-safe. fix!: Make HttpResponse.statusCode getter & setter thread-safe May 29, 2024
@sichanyoo sichanyoo changed the title fix!: Make HttpResponse.statusCode getter & setter thread-safe fix: Make HttpResponse.statusCode getter & setter thread-safe May 29, 2024
Copy link
Contributor

@jbelkins jbelkins left a comment

Choose a reason for hiding this comment

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

This is correct as far as thread-safety. Not sure how I feel about using DispatchQueue though - CRT generally does not use it, and our projects only use it where needed to interact with Foundation APIs that are based on it.

Since this fixes the problem though, I'm approving and we can revisit it later.

@sichanyoo sichanyoo merged commit 500da59 into main May 29, 2024
17 checks passed
@sichanyoo sichanyoo deleted the fix/remove-data-race branch May 29, 2024 17:35
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