Skip to content
Open
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
69 changes: 69 additions & 0 deletions components/http_foundation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,73 @@
return new StreamedJsonResponse(loadArticles());
}

.. _component-http-foundation-sse:

Streaming Server-Sent Events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The :class:`Symfony\\Component\\HttpFoundation\\EventStreamResponse` class
allows you to implement `Server-Sent Events (SSE)`_ - a standard for pushing
real-time updates from server to client over HTTP.

.. versionadded:: 7.3

The ``EventStreamResponse`` and ``ServerEvent`` classes were introduced in Symfony 7.3.

Basic usage with a generator::

use Symfony\Component\HttpFoundation\EventStreamResponse;
use Symfony\Component\HttpFoundation\ServerEvent;

$response = new EventStreamResponse(function (): iterable {
yield new ServerEvent('First message');
sleep(1);
yield new ServerEvent('Second message');
});

$response->send();

The ``EventStreamResponse`` automatically sets the required headers::

Content-Type: text/event-stream

Check failure on line 848 in components/http_foundation.rst

View workflow job for this annotation

GitHub Actions / Code Blocks

[PHP syntax] Syntax error, unexpected ':'
Cache-Control: no-cache

Check failure on line 849 in components/http_foundation.rst

View workflow job for this annotation

GitHub Actions / Code Blocks

[PHP syntax] Syntax error, unexpected ':'

Check failure on line 849 in components/http_foundation.rst

View workflow job for this annotation

GitHub Actions / Code Blocks

[PHP syntax] Syntax error, unexpected T_STRING
Connection: keep-alive

Check failure on line 850 in components/http_foundation.rst

View workflow job for this annotation

GitHub Actions / Code Blocks

[PHP syntax] Syntax error, unexpected T_STRING

The :class:`Symfony\\Component\\HttpFoundation\\ServerEvent` class represents an
individual SSE event following `the WHATWG SSE specification`_. It accepts the
following constructor arguments:

``data``
The event data (string or iterable for multi-line data).

``type``
The event type. Clients can listen for specific types using
``eventSource.addEventListener('type', ...)``.

``id``
The event ID. The browser sends this as ``Last-Event-ID`` header when
reconnecting, allowing you to resume from where the client left off.

``retry``
The reconnection time in milliseconds. Tells the browser how long to wait
before reconnecting if the connection is lost.

``comment``
A comment line (prefixed with ``:`` in the SSE protocol). Useful for
keep-alive messages to prevent connection timeouts.

.. tip::

For usage in Symfony controllers with additional features like automatic
reconnection handling, see :ref:`controller-server-sent-events`.

.. warning::

SSE keeps HTTP connections open, consuming server resources for each client.
For applications with many concurrent connections, consider using
:doc:`Mercure </mercure>` instead, which uses a dedicated hub for efficient
connection management.

.. _component-http-foundation-serving-files:

Serving Files
Expand Down Expand Up @@ -1086,3 +1153,5 @@
.. _RFC 8674: https://tools.ietf.org/html/rfc8674
.. _Doctrine Batch processing: https://www.doctrine-project.org/projects/doctrine-orm/en/2.14/reference/batch-processing.html#iterating-results
.. _`CHIPS`: https://developer.mozilla.org/en-US/docs/Web/Privacy/Partitioned_cookies
.. _`Server-Sent Events (SSE)`: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events
.. _`the WHATWG SSE specification`: https://html.spec.whatwg.org/multipage/server-sent-events.html
117 changes: 117 additions & 0 deletions controller.rst
Original file line number Diff line number Diff line change
Expand Up @@ -951,6 +951,121 @@
``sendEarlyHints()`` method also returns the ``Response`` object, which you
must use to create the full response sent from the controller action.

.. _controller-server-sent-events:

Streaming Server-Sent Events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

`Server-Sent Events (SSE)`_ is a standard that allows a server to push updates
to the client over a single HTTP connection. It's a simple and efficient way
to send real-time updates from the server to the browser, such as live
notifications, progress updates, or data feeds.

.. versionadded:: 7.3

The ``EventStreamResponse`` and ``ServerEvent`` classes were introduced in Symfony 7.3.

The :class:`Symfony\\Component\\HttpFoundation\\EventStreamResponse` class
allows you to stream events to the client using the SSE protocol. It automatically
sets the required headers (``Content-Type: text/event-stream``, ``Cache-Control: no-cache``,
``Connection: keep-alive``) and provides a simple API to send events::

use Symfony\Component\HttpFoundation\EventStreamResponse;
use Symfony\Component\HttpFoundation\ServerEvent;

// ...

public function liveNotifications(): EventStreamResponse
{
return new EventStreamResponse(function (): iterable {
foreach ($this->getNotifications() as $notification) {
yield new ServerEvent($notification->toJson());

sleep(1); // simulate a delay between events
}
});
}

The :class:`Symfony\\Component\\HttpFoundation\\ServerEvent` class is a DTO
that represents an SSE event following `the WHATWG specification`_. You can
customize each event using its constructor arguments::

// basic event with just data
yield new ServerEvent('Some message');

// event with a custom type (client listens via addEventListener('my-event', ...))
yield new ServerEvent(
data: json_encode(['status' => 'completed']),
type: 'my-event'
);

// event with an ID (useful for resuming streams with Last-Event-ID header)
yield new ServerEvent(
data: 'Update content',
id: 'event-123'
);

// event that tells the client to retry after a specific time (in milliseconds)
yield new ServerEvent(
data: 'Retry info',
retry: 5000
);

// event with a comment (can be used for keep-alive)
yield new ServerEvent(comment: 'keep-alive');

For use cases where generators are not feasible, you can use the
:method:`Symfony\\Component\\HttpFoundation\\EventStreamResponse::sendEvent`
method for manual control::

use Symfony\Component\HttpFoundation\EventStreamResponse;
use Symfony\Component\HttpFoundation\ServerEvent;

// ...

public function liveProgress(): EventStreamResponse
{
return new EventStreamResponse(function (EventStreamResponse $response) {
$redis = new \Redis();
$redis->connect('127.0.0.1');
$redis->subscribe(['message'], function (/* ... */, string $message) use ($response) {
$response->sendEvent(new ServerEvent($message));

Check failure on line 1032 in controller.rst

View workflow job for this annotation

GitHub Actions / Code Blocks

[PHP syntax] Syntax error, unexpected ',', expecting T_VARIABLE
});
});
}

On the client side, you can listen to events using the native ``EventSource`` API:

.. code-block:: javascript

const eventSource = new EventSource('/live-notifications');

// listen to all events (without a specific type)
eventSource.onmessage = (event) => {
console.log('Received:', event.data);
};

// listen to events with a specific type
eventSource.addEventListener('my-event', (event) => {
console.log('My event:', JSON.parse(event.data));
});

// handle connection errors
eventSource.onerror = (error) => {
console.error('SSE error:', error);
eventSource.close();
};

.. warning::

``EventStreamResponse`` is designed for small applications with limited
concurrent connections. Because SSE keeps HTTP connections open, it consumes
server resources (memory and connection limits) for each connected client.

For high-traffic applications that need to broadcast updates to many clients
simultaneously, consider using :doc:`Mercure </mercure>`, which is built on
top of SSE but uses a dedicated hub to manage connections efficiently.

Final Thoughts
--------------

Expand Down Expand Up @@ -991,3 +1106,5 @@
.. _`Validate Filters`: https://www.php.net/manual/en/filter.constants.php
.. _`phpstan/phpdoc-parser`: https://packagist.org/packages/phpstan/phpdoc-parser
.. _`phpdocumentor/type-resolver`: https://packagist.org/packages/phpdocumentor/type-resolver
.. _`Server-Sent Events (SSE)`: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events
.. _`the WHATWG specification`: https://html.spec.whatwg.org/multipage/server-sent-events.html
11 changes: 11 additions & 0 deletions mercure.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@ thanks to a specific HTTP header).

All these features are supported in the Symfony integration.

.. tip::

For simpler use cases with limited concurrent connections (e.g. progress
updates, admin dashboards, or internal tools), you can use native
Server-Sent Events directly via Symfony's ``EventStreamResponse`` class.
See :ref:`controller-server-sent-events` for more information.

Use Mercure when you need its advanced features like authorization,
automatic reconnection with message recovery, broadcasting to many clients,
or high-traffic scalability.

`In this recording`_ you can see how a Symfony web API leverages Mercure
and API Platform to update in live a React app and a mobile app (React Native)
generated using the API Platform client generator.
Expand Down
Loading