Live updates
With live updates, open pages show what changed the moment it changes: the free places on the website's offer list, and the places, waiting lists and attendances in the admin. fepli tells the browsers through a Mercure hub that runs inside the web container. Without it, the pages work as before and ask for the numbers when they load.
What changes
- The website's offer list. The free places and the „Sofort buchbar“ label change in the open page as families apply, withdraw or get a place. Everybody sees them: they are what the list shows anyway.
- The admin. The places in an offer's head, in the offer list and among its facts, and the attendances in an edition's head, renew when an attendance changes them. Only accounts that may see an offer hear of it: admins of every offer of their tenant, hosts of their own offers and of the offers shared with them.
What the hub hands on is ids and numbers, never names, addresses or text. A browser that hears of a change in the admin asks fepli for the new numbers, and fepli checks that request as it checks any page.
How it works
- The hub is part of the image. The web server of the image, FrankenPHP, has a Mercure hub built in. You switch it on with a block in its configuration and two keys. A browser that keeps its connection to the hub open holds no PHP process: the hub is a separate part of the server.
- One connection per browser. The tabs of a browser share one connection to the hub, however many are open.
- After the response. fepli publishes after it has answered the request that changed something, and after it has cleared the cache for it. Nobody waits for the hub, and a browser that asks for the new numbers gets them.
- Nothing breaks without it. A hub that is down costs a warning in the log,
A live update was not published, and nothing else: the request and the job that changed something go through. The browsers reconnect by themselves.
Switch it on
1. Generate two keys
openssl rand -base64 48
Run it twice: one key for publishing, one for the tokens that let an admin's browser hear the admin's changes. Add both to fepli.env, which the web, the worker and the cron read:
fepli.env
MERCURE_PUBLISHER_JWT_KEY=…
MERCURE_SUBSCRIBER_JWT_KEY=…
2. Switch on the hub in the web container
The hub's configuration is several lines, which an env file can't hold. Give it to the web service in compose.yaml:
compose.yaml
web:
<<: *fepli
environment:
CADDY_SERVER_EXTRA_DIRECTIVES: |
mercure {
transport local
publisher_jwt {env.MERCURE_PUBLISHER_JWT_KEY}
subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY}
cookie_name fepli_live
anonymous
heartbeat 30s
write_timeout 600s
}
anonymouslets every browser hear the website's free places. The admin's changes reach only browsers with a token: the admin sets one as a cookie named incookie_name, for 15 minutes, and renews it.transport localkeeps nothing: a browser that lost its connection asks for the numbers once when it is back.heartbeatkeeps an idle connection alive through proxies;write_timeoutrenews every connection after ten minutes.
The hub answers at /.well-known/mercure on every domain of the installation. fepli names it in the pages' <meta name="fepli-live-hub"> once MERCURE_PUBLISHER_JWT_KEY is set.
3. Tell the worker and the cron where the hub is
The worker and the cron publish too, for the changes their jobs make: a lottery, a waitlist that moves up. They run no hub of their own, so they send their updates to the web container. Add its address to fepli.env; the web container publishes to its own hub and ignores it:
fepli.env
MERCURE_URL=http://web/.well-known/mercure
4. Let the stream through your proxy
The connection to the hub stays open and receives an event now and then. Nothing between the browser and the web container may buffer it or close it while it is quiet.
- Varnish. The Varnish image passes
/.well-known/mercurestraight through to the web container, without caching it or touching its cookies. Use the current image. - Caddy as in the Compose setup passes the stream on as it is.
- Other proxies need buffering off for
/.well-known/mercureand an idle timeout longer than the heartbeat of 30 seconds. With nginx:proxy_buffering off;andproxy_read_timeout 1h;for that location.
Restart the containers: docker compose up -d.
Variables
- Name
MERCURE_PUBLISHER_JWT_KEY- Type
- string
- Description
The key fepli signs its updates with, and the hub checks them with. Empty switches live updates off.
- Name
MERCURE_SUBSCRIBER_JWT_KEY- Type
- string
- Description
The key of the tokens an admin's browser shows the hub. Empty switches the admin's live updates off; the website's stay on.
- Name
MERCURE_URL- Type
- URL
- Description
Where the worker and the cron send their updates, inside the network:
http://web/.well-known/mercure. The web container ignores it.
- Name
MERCURE_PUBLIC_URL- Type
- URL
- Description
Where browsers connect to the hub. Default:
/.well-known/mercureon the domain of the page.
- Name
MERCURE_COOKIE_NAME- Type
- string
- Description
The cookie of the admin's token. Default:
fepli_live, the hub'scookie_nameabove. Change both together, or neither.
Check it
-
The page names the hub. The source of a page of the website has
<meta name="fepli-live-hub" …>. An admin page has it withdata-subscribeas well. -
The hub answers. This request stays open and prints
:every 30 seconds:curl -N 'https://example.fepli.eu/.well-known/mercure?topic=/fepli/editions/<edition>/places'<edition>is the edition's UUID in its short base58 form, as in the address of the offer list'slive.json(in the browser's network tab). On a multi-tenant installation,fepliis the tenant's slug. Change an offer's maximum number of participants in the admin, and the request prints anevent: places. -
One connection per browser. In the browser's network tab: one request to
/.well-known/mercure, however many tabs of the installation are open. In the admin, a request to/admin/_live/tokencomes before it.
Limits
- One web container. The hub keeps its connections in the web container it runs in. With more than one web container, an update reaches only the browsers connected to the container that published it. Don't switch live updates on for such an installation yet.
- Updates. Restarting the web container ends every connection. The browsers connect again within seconds and ask for the numbers once.
- Rights that change. A token holds for 15 minutes, and the hub checks it when a browser connects. An account whose access to an offer is taken away hears of its changes until its browser connects again, at most a quarter of an hour. What reaches it is the offer's id.
Switch it off
Empty MERCURE_PUBLISHER_JWT_KEY and remove CADDY_SERVER_EXTRA_DIRECTIVES, then restart the containers. Pages that Varnish still holds keep naming the hub until they are rendered again; their browsers find no hub and ask for the numbers as before.