Skip to content

Bug fix for S3AsyncClient.putObject hangs if there is a connection reset set while uploading of object #3535

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

Merged
merged 4 commits into from
Nov 15, 2022

Conversation

joviegas
Copy link
Contributor

@joviegas joviegas commented Nov 3, 2022

Motivation and Context

  • Bug fix for S3AsyncClient.putObject hangs if there is a connection reset while uploading of objects

Root Cause

  • PR# 1481 added logic to skip RunError steps in ResponseHandler.#notifyIfResponseNotCompleted.
  • In the case of PutObject call, the putObject request sends Http100Continue
  • When Http100Continue is sent HttpResponseStatus CONTINUE = newStatus(100, "Continue") is received , which actually ignores the body, sends the lastByte and immediately starts reading the request stream.
  • If there was a connection reset because of PR# 1481 it only checked that lastByte was set and thus skipped the Run Error steps.
  • Since it skipped RunError the error was not propagated and it got stuck.

Modifications

  • Removed LastHttpContentHandler and added the setting of LAST_HTTP_CONTENT_RECEIVED_KEY for read specific case when there is a GET request and data is read , this will not impact PUT request where request streams are read even after receiving Last byte as part of put request

Testing

  • Tested by sending a huge object in S3Asycn.putObject and then disconnecting from VPN in between transfer. Expected outcome is it throws TimeOut Exceptions rather than waiting infinitely.
  • Added J units for this case by mocking server disconnects when transfer is in progress.

Screenshots (if appropriate)

Types of changes

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

Checklist

  • I have read the CONTRIBUTING document
  • Local run of mvn install succeeds
  • My code follows the code style of this project
  • My change requires a change to the Javadoc documentation
  • I have updated the Javadoc documentation accordingly
  • I have added tests to cover my changes
  • All new and existing tests passed
  • I have added a changelog entry. Adding a new entry must be accomplished by running the scripts/new-change script and following the instructions. Commit the new file created by the script in .changes/next-release with your changes.
  • My change is to implement 1.11 parity feature and I have updated LaunchChangelog

License

  • I confirm that this pull request can be released under the Apache 2 license

@@ -211,7 +213,7 @@ private void handleCancelled(ChannelHandlerContext ctx, InT msg) {
private void handleReadHttpContent(ChannelHandlerContext ctx, HttpContent content) {
if (!ignoreBodyRead) {
if (content instanceof LastHttpContent) {

ctx.channel().attr(LAST_HTTP_CONTENT_RECEIVED_KEY).set(true);
Copy link
Contributor

@cenedhryn cenedhryn Nov 3, 2022

Choose a reason for hiding this comment

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

This is a nice simplification of the logic.

Do we want to move the logging statement over too?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done, added Debug log same as before

@joviegas joviegas force-pushed the feature/master/joviegas_async_hang_bug branch from 8d076f8 to fd1287e Compare November 3, 2022 17:47
@joviegas joviegas force-pushed the feature/master/joviegas_async_hang_bug branch from fd1287e to 267eee9 Compare November 3, 2022 17:49
@@ -211,7 +215,8 @@ private void handleCancelled(ChannelHandlerContext ctx, InT msg) {
private void handleReadHttpContent(ChannelHandlerContext ctx, HttpContent content) {
if (!ignoreBodyRead) {
if (content instanceof LastHttpContent) {

ctx.channel().attr(LAST_HTTP_CONTENT_RECEIVED_KEY).set(true);
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we know in what situations ignoreBodyRead is set to true?

Copy link
Contributor Author

@joviegas joviegas Nov 3, 2022

Choose a reason for hiding this comment

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

ignoreBodyRead is true when we get 200 OK and there is nothing to read

Example

ignoreBodyRead in False state while handleReadHttpContent

In the case of GetObject

  1. We get 200 OK
  2. Then we read the data
  3. Last byte received

Now since get has data to read the ignoreBodyRead is in false state because this fails.

When set to true

In the case of PutObject

  1. We get 200 OK
  2. Then we SEND the data, nothing to read from service
  3. Last byte received

Now since Put has no data to read the ignoreBodyRead is in true state because this passes.

It makes sense to set the LastByte flag true irrespective of ignoreBodyRead status

/**
* {@link AttributeKey} to keep track of whether we have received the {@link LastHttpContent}.
*/
public static final AttributeKey<Boolean> LAST_HTTP_CONTENT_RECEIVED_KEY = NettyUtils.getOrCreateAttributeKey(
Copy link
Contributor

@zoewangg zoewangg Nov 3, 2022

Choose a reason for hiding this comment

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

Should we rename it to STREAMING_COMPLETE_KEY? Alternatively, we can update the description of this field to make it clear that it indicates streaming has finished

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

import org.reactivestreams.Subscription;
import software.amazon.awssdk.http.async.SdkHttpContentPublisher;

public class SdkTestHttpContentPublisher implements SdkHttpContentPublisher {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we use the existing SimpleHttpContentPublisher or something from RxJava?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

SimpleHttpContentPublisher is in core and netty didnot have core dependency, I did not find anything from RxJava, will keep looking out for it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added SimpleHttpContentPublisher in http-client-tests since adding in test-utils is casuing cyclic dependency.

@joviegas joviegas force-pushed the feature/master/joviegas_async_hang_bug branch from 0c1e18b to be709d2 Compare November 4, 2022 00:24
…E_KEY and setting it irrespective of ignoreBodyRead flag
@joviegas joviegas force-pushed the feature/master/joviegas_async_hang_bug branch from be709d2 to e4af9ba Compare November 4, 2022 18:52
if (content instanceof LastHttpContent) {

if (lastHttpContent) {
logger.debug(ctx.channel(), () -> "Received LastHttpContent " + ctx.channel());
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe moving this log statement to line 218?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@sonarqubecloud
Copy link

SonarCloud Quality Gate failed.    Quality Gate failed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 4 Code Smells

64.7% 64.7% Coverage
5.0% 5.0% Duplication

@joviegas joviegas merged commit 876adfd into master Nov 15, 2022
@joviegas joviegas deleted the feature/master/joviegas_async_hang_bug branch December 20, 2022 00:38
aws-sdk-java-automation added a commit that referenced this pull request Jan 2, 2025
…5b148a627

Pull request: release <- staging/42c674bc-70ed-49a8-9013-a745b148a627
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.

3 participants