Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions gems/aws-sdk-s3/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
Unreleased Changes
------------------

* Issue - Remove `:thread_count` from transfer options even when a custom `:executor` is configured on `TransferManager`, fixing an `ArgumentError` raised on single-part `upload_file` calls.

* Issue - Fix `:thread_count` being ignored by the deprecated `Object#download_file`, which always used the default thread count.

1.232.2 (2026-09-25)
------------------

Expand Down
2 changes: 1 addition & 1 deletion gems/aws-sdk-s3/lib/aws-sdk-s3/customizations/object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ def upload_file(source, options = {})
# @see Client#head_object
def download_file(destination, options = {})
download_opts = options.merge(bucket: bucket_name, key: key)
executor = DefaultExecutor.new(max_threads: download_opts.delete([:thread_count]))
executor = DefaultExecutor.new(max_threads: download_opts.delete(:thread_count))
begin
downloader = FileDownloader.new(client: client, executor: executor)
Aws::Plugins::UserAgent.metric('RESOURCE_MODEL') do
Expand Down
16 changes: 10 additions & 6 deletions gems/aws-sdk-s3/lib/aws-sdk-s3/transfer_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,8 @@ def initialize(options = {})
# * `:errors` - Array of errors for failed downloads (only present when failures occur)
def download_directory(destination, bucket:, **options)
Aws::Plugins::UserAgent.metric('S3_TRANSFER', 'S3_TRANSFER_DOWNLOAD_DIRECTORY') do
executor = @executor || DefaultExecutor.new(max_threads: options.delete(:thread_count))
thread_count = options.delete(:thread_count)
executor = @executor || DefaultExecutor.new(max_threads: thread_count)
begin
downloader = DirectoryDownloader.new(client: @client, executor: executor, logger: @logger)
downloader.download(destination, bucket: bucket, **options)
Expand Down Expand Up @@ -247,7 +248,8 @@ def download_directory(destination, bucket:, **options)
# @see Client#head_object
def download_file(destination, bucket:, key:, **options)
download_opts = options.merge(bucket: bucket, key: key)
executor = @executor || DefaultExecutor.new(max_threads: download_opts.delete(:thread_count))
thread_count = download_opts.delete(:thread_count)
executor = @executor || DefaultExecutor.new(max_threads: thread_count)
begin
downloader = FileDownloader.new(client: @client, executor: executor)
downloader.download(destination, download_opts)
Expand Down Expand Up @@ -365,7 +367,8 @@ def download_file(destination, bucket:, key:, **options)
# * `:errors` - Array of error objects for failed uploads (only present when failures occur)
def upload_directory(source, bucket:, **options)
Aws::Plugins::UserAgent.metric('S3_TRANSFER', 'S3_TRANSFER_UPLOAD_DIRECTORY') do
executor = @executor || DefaultExecutor.new(max_threads: options.delete(:thread_count))
thread_count = options.delete(:thread_count)
executor = @executor || DefaultExecutor.new(max_threads: thread_count)
begin
uploader = DirectoryUploader.new(client: @client, executor: executor, logger: @logger)
uploader.upload(source, bucket, **options.merge(http_chunk_size: resolve_http_chunk_size(options)))
Expand Down Expand Up @@ -450,8 +453,8 @@ def upload_directory(source, bucket:, **options)
def upload_file(source, bucket:, key:, **options)
upload_opts = options.merge(bucket: bucket, key: key)
http_chunk_size = resolve_http_chunk_size(upload_opts)

executor = @executor || DefaultExecutor.new(max_threads: upload_opts.delete(:thread_count))
thread_count = upload_opts.delete(:thread_count)
executor = @executor || DefaultExecutor.new(max_threads: thread_count)
begin
uploader = FileUploader.new(
multipart_threshold: upload_opts.delete(:multipart_threshold),
Expand Down Expand Up @@ -521,7 +524,8 @@ def upload_file(source, bucket:, key:, **options)
# @see Client#upload_part
def upload_stream(bucket:, key:, **options, &block)
upload_opts = options.merge(bucket: bucket, key: key)
executor = @executor || DefaultExecutor.new(max_threads: upload_opts.delete(:thread_count))
thread_count = upload_opts.delete(:thread_count)
executor = @executor || DefaultExecutor.new(max_threads: thread_count)
begin
uploader = MultipartStreamUploader.new(
client: @client,
Expand Down
6 changes: 6 additions & 0 deletions gems/aws-sdk-s3/spec/object/download_file_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ module S3
expect { subject.download_file(path) }.to raise_error(Aws::S3::Errors::NoSuchKey)
end

it 'respects the thread_count option' do
custom_thread_count = 20
expect(DefaultExecutor).to receive(:new).with(max_threads: custom_thread_count).and_call_original
subject.download_file(path, thread_count: custom_thread_count)
end

it 'shuts down the internally-created executor when download raises', thread_report_on_exception: false do
client.stub_responses(:head_object, 'NoSuchKey')
executor = nil
Expand Down
Loading