Skip to content

Conversation

@alextwoods
Copy link
Contributor

Fix bug in FileAsyncRequestBody where inflight parts were negative

Motivation and Context

Fix bug in S3 Multipart uploads with FileAsyncRequestBody - ensure that concurrency is limited correctly by bufferSizeInBytes.

Fixes: #6539

Modifications

  • Replaces the atomic counter for in flight parts with a synchronized set - this ensures that when a part is "finished" (completed/canceled) multiple times, that the number of in flight parts remains consistent.

The ContentLengthAwareSubscriber calls cancel on the subscription (see code linked) which can result in multiple calls to the startNextRequestBody for the same part - causing the old numAsyncRequestBodiesInFlight to be decremented multiple times and leading to it being negative.

Testing

Updated unit tests (added additional condition) + manual test.

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
  • 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.

License

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

@alextwoods alextwoods requested a review from a team as a code owner November 13, 2025 18:00
// will never be invoked, and if the current buffer is full, the publisher will stop
// sending new FileAsyncRequestBody, leading to uncompleted future.
.doAfterOnCancel(() -> startNextRequestBody(simplePublisher))
.doAfterOnCancel(() -> startNextRequestBody(simplePublisher, position))
Copy link
Contributor

Choose a reason for hiding this comment

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

Another possible fix, to avoid keep track of inflight in a collection, would be to have a flag in the FileAsyncRequestBodyWrapper that tracks if the next request was started or not, and call startNextRequestBody only when it was not.

But both feels a little bit like a bandaid solution, is there a way to completely avoid the multiple calls to the startNextRequestBody?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah - that was my fix - which seems to be working.

I'm not sure there is a way for us to avoid multiple onCancel being called - and I'm not sure that we'd ever want to make the assumption either - the Reactive Stream Spec (rule 3.7) requires canancls after the first to be nops:

After the Subscription is cancelled, additional Subscription.cancel() MUST be NOPs.

Copy link
Contributor

Choose a reason for hiding this comment

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

Good point on reactive specs, yeah you are correct we should make sure anyways it is NOOP for multiple calls

@sonarqubecloud
Copy link

@alextwoods
Copy link
Contributor Author

s3-regression-tests-upload-async keeps failing with timeouts on MRAP tests:

2025-11-13 20:50:04 [main] INFO  software.amazon.awssdk.services.s3.regression.upload.UploadAsyncRegressionTesting:43 - Error while executing FlattenUploadConfig(bucketType=MRAP, forcePathStyle=false, requestChecksumValidation=WHEN_REQUIRED, bodyType=BUFFERS_REMAINING, contentSize=LARGE, payloadSigning=true). Error message: software.amazon.awssdk.core.exception.ApiCallTimeoutException: Client execution did not complete before the specified timeout configuration: 30000 millis

These failures happen for all body types (see above example where body type is BUFFERS_REMAINING) - these non file type bodies don't use the FileAsycRequestBody that is being changed. Possibly an MRAP related issue - will retry later.

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.

S3 multipart upload using FileAsyncRequestBody is not limited by configuration: bufferSizeInBytes

2 participants