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
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,22 @@ static AsyncRequestBody fromRemainingByteBuffersUnsafe(ByteBuffer... byteBuffers
* <p>An {@link ExecutorService} is required in order to perform the blocking data reads, to prevent blocking the
* non-blocking event loop threads owned by the SDK.
*
* <p><b>Executor Guidance:</b> The provided executor is used to run a blocking task that reads from the input stream and
* pushes data to the HTTP channel. If the executor has fewer threads than the number of concurrent requests using it,
* tasks are serialized — one slow or failing request may block other requests from writing data in a timely manner,
* leading to idle HTTP connections that the server may close before data can be written. This may result in an
* unrecoverable write timeout loop where every retry also fails.
*
* <p>To avoid this:
* <ul>
* <li>Use a <b>dedicated</b> executor for SDK input stream requests — do not share it with other blocking work
* in your application, as competing tasks may delay data writes and cause the same issue.</li>
* <li>Size the executor's thread pool to at least the maximum number of concurrent requests.</li>
* </ul>
*
* <p>It is also recommended to configure an API call timeout via
* {@code ClientOverrideConfiguration.builder().apiCallTimeout()} to bound the total time spent on retries.
*
* @param inputStream The input stream containing the data to be sent
* @param contentLength The content length. If a content length smaller than the actual size of the object is set, the client
* will truncate the stream to the specified content length and only send exactly the number of bytes
Expand All @@ -390,7 +406,9 @@ static AsyncRequestBody fromInputStream(InputStream inputStream, Long contentLen

/**
* Creates an {@link AsyncRequestBody} from an {@link InputStream} with the provided
* {@link AsyncRequestBodySplitConfiguration}.
* {@link AsyncRequestBodyFromInputStreamConfiguration}.
*
* <p>See {@link #fromInputStream(InputStream, Long, ExecutorService)} for guidance on executor.
*/
static AsyncRequestBody fromInputStream(AsyncRequestBodyFromInputStreamConfiguration configuration) {
Validate.notNull(configuration, "configuration");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ public interface Builder extends CopyableBuilder<AsyncRequestBodyFromInputStream
/**
* Configures the {@link ExecutorService} to perform the blocking data reads.
*
* <p>It is recommended to have a dedicated executor for SDK input stream requests and have as many threads as the
* number of concurrent requests sharing it. Using an undersized or shared executor may lead to unrecoverable failures.
* See {@link AsyncRequestBody#fromInputStream(InputStream, Long, ExecutorService)} for details.
*
* @param executor the executor
* @return This object for method chaining.
*/
Expand Down
Loading