PHPackages                             prsw/amphp-bundle - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [HTTP &amp; Networking](/categories/http)
4. /
5. prsw/amphp-bundle

ActiveSymfony-bundle[HTTP &amp; Networking](/categories/http)

prsw/amphp-bundle
=================

Symfony bundle providing an AMPHP HTTP server runtime

v0.1.0(2mo ago)17MITPHPPHP &gt;=8.4

Since May 16Pushed 1mo agoCompare

[ Source](https://github.com/praswicaksono/amphp-bundle)[ Packagist](https://packagist.org/packages/prsw/amphp-bundle)[ RSS](/packages/prsw-amphp-bundle/feed)WikiDiscussions main Synced 3w ago

READMEChangelog (1)Dependencies (19)Versions (2)Used By (0)

AmphpBundle
===========

[](#amphpbundle)

Replaces PHP-FPM with a long-running async HTTP server for Symfony. All I/O is non-blocking and fiber-based. No more PHP-FPM process overhead.

Features
--------

[](#features)

- **Async HTTP server** — built on [amphp/http-server](https://github.com/amphp/http-server)
- **Async Doctrine** — non-blocking MySQL/PostgreSQL driver with connection pooling
- **WebSocket server** — attribute-driven endpoints, no Symfony boot for handshake
- **SSE streaming** — server-sent events via `SseResponse`
- **Generator-based streaming** — async `StreamedResponse` with `yield`
- **Hot reload** — `--dev --watch` restarts on file changes (requires `fswatch`)
- **Cluster mode** — multi-worker with process supervision and graceful restart
- **Prometheus metrics** — `/metrics` endpoint with `MetricCollectorInterface`
- **Liveness / Readiness probes** — `/healthz` (no Symfony boot), `/readyz` (full stack)
- **Async Redis** — cache, session handler, messenger transport
- **Async Mailer** — SMTP + HTTP via `amphp/http-client`

Quick Start
-----------

[](#quick-start)

### 1. Install

[](#1-install)

```
composer require prsw/amphp-bundle "@dev"
```

Register the bundle if you are not using symfony flex in `config/bundles.php`:

```
return [
    PRSW\AmphpBundle\AmphpBundle::class => ['all' => true],
];
```

### 2. Start the Server

[](#2-start-the-server)

```
# Production — cluster mode with process supervision
php bin/console amphp:start --workers=4

# Development — single worker, hot reload
php bin/console amphp:start --dev --watch
```

Press Ctrl+C to stop.

### 3. Add a WebSocket Endpoint

[](#3-add-a-websocket-endpoint)

Create a class with the `#[WebsocketEndpoint]` attribute — no YAML needed:

```
use Amp\Websocket\Server\WebsocketClientHandler;
use Amp\Websocket\Server\WebsocketClientGateway;
use Amp\Websocket\WebsocketClient;
use PRSW\AmphpBundle\Websocket\Attribute\WebsocketEndpoint;

#[WebsocketEndpoint(path: '/chat')]
class ChatHandler implements WebsocketClientHandler
{
    public function handleClient(
        WebsocketClient $client,
        \Amp\Http\Server\Request $request,
        \Amp\Http\Server\Response $response,
    ): void {
        $gateway = new WebsocketClientGateway();
        $gateway->addClient($client);
        $gateway->broadcastText('User joined');

        foreach ($client as $message) {
            $gateway->broadcastText($message->buffer());
        }
    }
}
```

The bundle auto-discovers `#[WebsocketEndpoint]` handlers at startup.

CLI Options
-----------

[](#cli-options)

OptionShortDescriptionDefault`--workers``-w`Number of worker processesCPU count`--max-requests``-r`Requests per worker before restart`1000``--host`Bind address`127.0.0.1``--port``-p`Bind port`8080``--shutdown-timeout``-t`Drain timeout (seconds)`1``--dev`Single worker, `--env=dev`, `--debug=true``--watch`File watcher + auto-restart (needs `--dev`)Configuration
-------------

[](#configuration)

```
# config/packages/amphp.yaml
amphp:
    host: '127.0.0.1'
    port: 8080
    workers: 0                        # 0 = auto-detect CPU count
    max_requests: 1000                # 0 = never restart
    shutdown_timeout: 5               # drain timeout before force-stop
    gc_interval: 30                   # PHP cycle collector (0 = off)

    dbal:
        max_connections: 100          # connection pool size
        idle_timeout: 60              # close idle connections after N seconds
        ping_interval: 30             # keepalive ping interval (0 = every request)

    static_files:
        enabled: true
        public_dir: null              # defaults to %kernel.project_dir%/public
        indexes: ['index.html', 'index.htm']
        expires_period: 604800

    tls:
        enabled: false
        cert_file: null
        key_file: null
        # See docs/tls.md for full TLS config

    readiness:
        enabled: true
        check_db: true

    websocket:
        enabled: true                 # set false to disable WebSocket entirely
```

> DBAL pool settings from `amphp.dbal` are automatically wired into Doctrine's `driverOptions`. Keep `max_connections` below your MySQL server's limit (`SHOW VARIABLES LIKE 'max_connections'`; default 151).

Per-Request Cleanup (Priority Reset System)
-------------------------------------------

[](#per-request-cleanup-priority-reset-system)

After each request, the bundle runs a chain of resetters to release resources and prevent state leaking between requests. Built-in resetters handle the Doctrine connection pool and debug logger; you can add your own via `PriorityResetInterface`.

### How It Works

[](#how-it-works)

1. `SymfonyRequestHandler` calls `RequestResetter::reset()` in the `finally` block.
2. `RequestResetter` sorts all tagged services by priority (highest first) and calls `reset()` on each.
3. Built-in priorities:
    - `DatabaseResetter` — **100** (releases pooled DB connection + FiberLocal entries)
    - User-defined — **-255 to 255** (your custom resetters)
    - `DebugLoggerResetter` — **-255** (clears debug logs)

### Adding a Custom Resetter

[](#adding-a-custom-resetter)

Create a class implementing `PriorityResetInterface`:

```
use PRSW\AmphpBundle\Runtime\Bridge\PriorityResetInterface;
use Symfony\Contracts\Service\ResetInterface;

final class MyConnectionResetter implements PriorityResetInterface
{
    public function __construct(
        private readonly MyConnectionPool $pool,
    ) {}

    public function reset(): void
    {
        $this->pool->releaseConnections();
    }

    public function getPriority(): int
    {
        // Run after DatabaseResetter (100) but before DebugLoggerResetter (-255)
        return 50;
    }
}
```

That's it — no manual tagging or service registration needed. The bundle's `BootstrapIntegrationPass` auto-configures any service implementing `PriorityResetInterface` with the `amphp.resetter` tag, and `RequestResetter`discovers it automatically via the tagged iterator.

### Execution Order

[](#execution-order)

Higher priority numbers run first. Use the built-in constants as anchor points:

PriorityResetterWhen it runs100`DatabaseResetter`Release pooled connection, clear FiberLocal50User exampleCustom pool release0User exampleGeneral-purpose cleanup-255`DebugLoggerResetter`Clear debug logs (last)### Real-World Use Cases

[](#real-world-use-cases)

- Release custom connection pools (Redis, RabbitMQ, gRPC)
- Clear in-memory caches or request-scoped state
- Reset rate-limit counters or circuit breakers
- Close temporary file handles or streams

Built-in Endpoints
------------------

[](#built-in-endpoints)

PathTypeDescription`/healthz`AMPHP middlewareReturns `{"status":"alive"}` — no Symfony boot`/readyz`Symfony routeFull-stack readiness check`/metrics`Symfony routePrometheus metricsuser-definedWebSocket`#[WebsocketEndpoint]` handlersBenchmarks
----------

[](#benchmarks)

Results with `wrk -t1 -c100 -d30s`, 1 worker, APP\_ENV=prod, APP\_DEBUG=0:

EndpointRequests/sAvg LatencyDescription`/twig-test`**1,446**69 msTwig template render, no DB`/products`**392**254 msDoctrine DBAL query + Twig render (15 rows)Compared to PHP-FPM with the same Symfony app, the async server eliminates the PHP-FPM process spawn overhead and connection pool contention, yielding higher throughput under concurrent load.

SSE Streaming
-------------

[](#sse-streaming)

```
use PRSW\AmphpBundle\Bridge\Symfony\HttpFoundation\SseEvent;
use PRSW\AmphpBundle\Bridge\Symfony\HttpFoundation\SseResponse;

#[Route('/events')]
public function stream(): SseResponse
{
    return new SseResponse(function () {
        while (true) {
            yield new SseEvent(data: ['time' => time()], event: 'tick');
            \Amp\delay(1);
        }
    });
}
```

Generator-Based Streaming
-------------------------

[](#generator-based-streaming)

```
#[Route('/stream')]
public function stream(): StreamedResponse
{
    return new StreamedResponse(function () {
        $handle = yield \Amp\File\open('/path/to/file', 'r');
        while (null !== $chunk = yield $handle->read()) {
            yield $chunk;
        }
    });
}
```

Prometheus Metrics
------------------

[](#prometheus-metrics)

Implement `MetricCollectorInterface` (autotagged `amphp.metric_collector`):

```
use PRSW\AmphpBundle\Metrics\Metric;
use PRSW\AmphpBundle\Metrics\MetricCollectorInterface;

final class OrderMetrics implements MetricCollectorInterface
{
    public function collect(): array
    {
        return [
            new Metric('orders_total', 42.0, 'Total orders', 'counter', ['status' => 'completed']),
        ];
    }
}
```

Optional Integrations
---------------------

[](#optional-integrations)

FeaturePackagesAsync Doctrine (MySQL/PostgreSQL)`amphp/mysql` + `doctrine/orm`Async Redis cache / sessions / messenger`amphp/redis`Async Mailer (SMTP + HTTP)`symfony/mailer` + `amphp/http-client`WebSocket serverincluded with the bundleHot reload (`--watch`)`fswatch` (system package)

###  Health Score

37

—

LowBetter than 81% of packages

Maintenance88

Actively maintained with recent releases

Popularity6

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity41

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

69d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/023a0bd17758df473ae6dad9f07575a8d0a8c36b06e83396b5962aecba38c722?d=identicon)[PrasWicaksono](/maintainers/PrasWicaksono)

---

Top Contributors

[![praswicaksono](https://avatars.githubusercontent.com/u/603125?v=4)](https://github.com/praswicaksono "praswicaksono (5 commits)")

---

Tags

amphpasyncphpsymfony-bundlehttpasyncsymfonywebsocket

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/prsw-amphp-bundle/health.svg)

```
[![Health](https://phpackages.com/badges/prsw-amphp-bundle/health.svg)](https://phpackages.com/packages/prsw-amphp-bundle)
```

###  Alternatives

[laravel/framework

The Laravel Framework.

34.8k543.8M20.5k](/packages/laravel-framework)[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

585.6M600](/packages/shopware-core)[flow-php/flow

PHP ETL - Extract Transform Load - Data processing framework

85036.3k](/packages/flow-php-flow)[shopware/platform

The Shopware e-commerce core

3.4k1.5M3](/packages/shopware-platform)[api-platform/core

Build a fully-featured hypermedia or GraphQL API in minutes!

2.6k51.2M353](/packages/api-platform-core)[oro/platform

Business Application Platform (BAP)

645143.5k116](/packages/oro-platform)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
