Skip to content

Commit ac48f35

Browse files
author
Arjan Lankhaar
committed
feat: added docs for custom HTTP client injection for S3 client creation
1 parent a27f8cc commit ac48f35

File tree

2 files changed

+109
-0
lines changed

2 files changed

+109
-0
lines changed

.wordlist.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ AppSystem
7474
Archlinux
7575
ArrayFacade
7676
AssociationField
77+
AsyncAws
7778
AsyncPaymentTransactionStruct
7879
AsynchronousPaymentHandlerInterface
7980
AudienceContext

guides/hosting/infrastructure/filesystem.md

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,114 @@ shopware:
221221

222222
If your S3 provider does not use buckets as subdomain like Minio in default configuration, you need to set `use_path_style_endpoint` to `true` inside `config`.
223223

224+
#### Custom HTTP client for S3
225+
226+
By default, the underlying AsyncAws S3 client creates its own HTTP client internally, which includes a `RetryableHttpClient` with an AWS-specific retry strategy. This handles transient errors like throttling (HTTP 429), server errors (HTTP 5xx), and other AWS-specific error codes automatically.
227+
228+
If you need to customize the HTTP behavior for S3 operations (e.g., timeouts, HTTP protocol version, or proxy settings), you can register a service with the ID `shopware.filesystem.s3.client`. When this service exists, Shopware injects it into both the filesystem adapter and pre-signed URL generation.
229+
230+
::: info
231+
When you provide a custom HTTP client, AsyncAws will **not** wrap it in its own `RetryableHttpClient`. If you need retry behavior, you must configure it yourself as shown below.
232+
:::
233+
234+
**Simple configuration** (custom timeouts, no retry handling):
235+
236+
```yaml
237+
# config/packages/framework.yaml
238+
framework:
239+
http_client:
240+
scoped_clients:
241+
s3.http_client:
242+
base_uri: '{your-s3-endpoint}'
243+
timeout: 30.0
244+
http_version: '1.1'
245+
```
246+
247+
```php
248+
// config/services.php
249+
<?php declare(strict_types=1);
250+
251+
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
252+
253+
return static function (ContainerConfigurator $configurator): void {
254+
$services = $configurator->services();
255+
256+
$services->alias('shopware.filesystem.s3.client', 's3.http_client');
257+
};
258+
```
259+
260+
**Recommended configuration** (custom settings with AWS retry support):
261+
262+
```yaml
263+
# config/packages/framework.yaml
264+
framework:
265+
http_client:
266+
scoped_clients:
267+
s3.http_client:
268+
base_uri: '{your-s3-endpoint}'
269+
timeout: 30.0
270+
http_version: '1.1'
271+
```
272+
273+
```php
274+
// config/services.php
275+
<?php declare(strict_types=1);
276+
277+
use AsyncAws\Core\HttpClient\AwsRetryStrategy;
278+
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
279+
use Symfony\Component\HttpClient\RetryableHttpClient;
280+
281+
use function Symfony\Component\DependencyInjection\Loader\Configurator\service;
282+
283+
return static function (ContainerConfigurator $configurator): void {
284+
$services = $configurator->services();
285+
286+
$services->set(AwsRetryStrategy::class);
287+
288+
$services->set('shopware.filesystem.s3.client', RetryableHttpClient::class)
289+
->args([
290+
service('s3.http_client'),
291+
service(AwsRetryStrategy::class),
292+
3, // max retries
293+
]);
294+
};
295+
```
296+
297+
This wraps your scoped client in a `RetryableHttpClient` with the same `AwsRetryStrategy` that AsyncAws uses by default, preserving retry behavior for AWS-specific transient errors while allowing you to control timeouts, HTTP version, and other transport-level settings.
298+
299+
**Without scoped clients** (standalone service definition with retry support):
300+
301+
```php
302+
// config/services.php
303+
<?php declare(strict_types=1);
304+
305+
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
306+
use Symfony\Component\HttpClient\HttpClient;
307+
use Symfony\Component\HttpClient\RetryableHttpClient;
308+
use Symfony\Contracts\HttpClient\HttpClientInterface;
309+
310+
use function Symfony\Component\DependencyInjection\Loader\Configurator\service;
311+
312+
return static function (ContainerConfigurator $configurator): void {
313+
$services = $configurator->services();
314+
315+
$services->set('s3.http_client', HttpClientInterface::class)
316+
->factory([HttpClient::class, 'create'])
317+
->args([
318+
['timeout' => 30],
319+
]);
320+
321+
$services->set('shopware.filesystem.s3.client', RetryableHttpClient::class)
322+
->args([
323+
service('s3.http_client'),
324+
null, // default retry strategy
325+
3, // max retries
326+
]);
327+
};
328+
```
329+
330+
This creates a plain HTTP client via `HttpClient::create()` with custom options and wraps it in a `RetryableHttpClient` with the default retry strategy.
331+
224332
### Google Cloud Platform
225333

226334
In order to use the Google Cloud Platform adapter you need to install the `league/flysystem-google-cloud-storage` package.

0 commit comments

Comments
 (0)