HN user

kdunglas

1,176 karma

Founder of Les-Tilleuls.coop (tech worker-owned cooperative).

Creator of mercure.rocks, frankenphp.dev and api-platform.com and vulcain.rocks. Co-maintainer of the Symfony framework and the Caddy web server.

[ website: https://dunglas.fr, twitter: https://twitter.com/dunglas ]

Posts18
Comments37
View on HN
thephp.foundation 1y ago

FrankenPHP (Caddy-based) is now officially supported by the PHP Foundation

kdunglas
20pts0
api-platform.com 1y ago

Show HN: API Platform for Laravel

kdunglas
10pts0
frankenphp.dev 2y ago

Show HN: Package PHP apps as standalone, self-executable binaries

kdunglas
29pts7
mastodon.social 3y ago

Twitter bans a popular French activist and the spokeswoman of the Pirate Party

kdunglas
27pts13
frankenphp.dev 3y ago

Show HN: FrankenPHP, an app server for PHP written in Go

kdunglas
368pts83
github.com 3y ago

Caddy 2.6 is out, the biggest release since Caddy 2

kdunglas
56pts7
dunglas.fr 4y ago

Show HN: A library to build Solid decentralized applications in PHP

kdunglas
4pts0
dunglas.fr 4y ago

Preventing CORS Preflight Requests Using Content Negotiation

kdunglas
1pts0
symfony.com 4y ago

Show HN: Automatic management of Docker images by the Symfony PHP framework

kdunglas
3pts0
code.gouv.fr 4y ago

Code.gouv.fr: 9000 open source programs published by the French public sector

kdunglas
67pts5
protonmail.com 4y ago

Clarifications regarding arrest of climate activist

kdunglas
470pts285
twitter.com 4y ago

Climate activist arrested after ProtonMail provided his IP address

kdunglas
1285pts584
opencollective.com 4y ago

Help open-source contributors escape Afghanistan

kdunglas
8pts1
www.reddit.com 7y ago

Official Push and Real-Time Capabilities for Symfony and API Platform (Mercure)

kdunglas
2pts0
github.com 7y ago

Show HN: React ESI, Blazing-Fast Server-Side Rendering for React and Next.js

kdunglas
5pts0
github.com 7y ago

A real-time chat app in 23 lines of Python and 35 lines of JavaScript

kdunglas
42pts8
mercure.rocks 7y ago

Protocol and a Go implem to push APIs updates in live from servers to clients

kdunglas
10pts0
symfony.com 7y ago

Introducing Symfony Panther: A Browser Testing and Web Scrapping Library for PHP

kdunglas
3pts0

Yes, as it 's "just" SSE, this works pretty well behind Cloudflare and other similar solutions. Mercure also automatically sends the NGINX-specific headers required to allow unbuffered connections.

Native mobile apps are also entirely supported. It's a very common use case. Most mobile languages have SSE client libraries.

Once the connection is upgraded, you loose all metadata included in the HTTP headers (because it’s not HTTP) and all protections relying on it. Also CORS and SOP can be bypassed: https://dev.to/pssingh21/websockets-bypassing-sop-cors-5ajm

Even very experienced teams make mistake with this kind of things. See for instance, this Kubernetes vulnerability: https://goteleport.com/blog/kubernetes-websocket-upgrade-sec...

Of course you can reimplement everything by hand (and you must if you use WebSockets), but with SSE/Mercure you don't have to because it's plain old HTTP.

Hi, Mercure author here.

Indeed that's how it works. One of the key point of the solution is that you don't need anything client-side. The native EventSource class is all you need (but you can use more advanced SSE client libraries if wanted).

Reconnection and state reconciliation are achieved automatically. The hub implements all the needed features: it stores sent events and automatically resend them at reconnection time if they have been lost. It's possible to do this transparently because browsers will automatically send the ID of the last received message in a Last-Event-ID header when reconnecting. This feature is just often not implemented by SSE servers (because it’s not trivial to do).

It's also possible to ask events received since a specific ID, matching one or several topics just by passing the query parameters defined in the protocol section.

By the way, we are working on a new website that will make these things more clear.

Hi, Mercure author here.

WebSockets are hard to secure (they totally bypass CORS as well as other browser built-in protections), don't work (yet) with HTTP/3 and for most use cases require to implement many features by yourself: reconnection in case of network failure, refetch of lost messages, authorization, topic mechanism…

Mercure, which is built on top of SSE (it's more an extension to SSE than an alternative to it) fix these issues.

However, SSE (as well as WebSockets) can be hard to use with stacks not designed to handle persistent connections such as PHP, serverless, most web servers proxying Ruby, Python etc apps. Even for languages designed to handle persistent connections, it's often more efficient and easier to manage persistent connections with ah-hoc software running on dedicated hardware.

That's what Mercure allows. Mercure provides a "hub", a server that will maintain the persistent connections with the browsers, store events, and re-send them in case of network issues (or if asked for old messages by a client). To broadcast a message to all connected users, the server app (or even a client) can just send a single POST request to the hub. The hub will also check that clients are authorized to subscribe or publish to a given topic (that's why JWT is used).

The reference implementation is written in Go, as a module for the Caddy web server, and his very efficient/optimized (it can handle thousands of persistent connections on very small machines).

Install a Mercure hub and you have all these features available without having to write any code. Client-side, no SDK is required, you can embrace the built-in EventSource JavaScript class.

A while ago I created Mercure: an open pub-sub protocol built on top of SSE that is a replacement for WebSockets-based solutions such as Pusher. Mercure is now used by hundreds of apps in production.

At the core of Mercure is the hub. It is a standalone component that maintains persistent SSE (HTTP) connections to the clients, and it exposes a very simple HTTP API that server apps and clients can use to publish. POSTed updates are broadcasted to all connected clients using SSE. This makes SSE usable even with technologies not able to maintain persistent connections such as PHP and many serverless providers.

Mercure also adds nice features to SSE such as a JWT-based authorization mechanism, the ability to subscribe to several topics using a single connection, events history, automatic state reconciliation in case of network issue…

I maintain an open-source hub written in Go (technically, a module for the Caddy web server) and a SaaS version is also available.

Docs and code are available on https://mercure.rocks

The Symfony framework (PHP) provides a similar feature, which also relies on LISTEN/NOTIFY and FOR UPDATE SKIP LOCKED: https://symfony.com/doc/current/messenger.html#doctrine-tran...

It also supports many other backends including AMQP, Beanstalkd, Redis and various cloud services.

This component, called Messenger, can be installed as a standalone library in any PHP project.

(Disclaimer: I’m the author of the PostgreSQL transport for Symfony Messenger).

This script is entirely optional and is only used to create static builds of FrankenPHP or to create self-executable PHP apps. It doesn't require a Docker image but does need some system dependencies.

It is not necessary to create a standard (dynamically linked) build of FrankenPHP and isn't used in the Docker images we provide: https://frankenphp.dev/docs/compile/

Optionally, you can embed the PHP scripts in the final binary using a Go feature similar to `include_bytes`: https://frankenphp.dev/docs/embed/

But for PHP, it's even simpler: PHP is available as a C library, and we just use it. (libphp can be embedded using static compilation, or used as a dynamic library, we support both).

This means that in addition to any PSR-7 implementation, you can run apps using HttpFoundation (Symfony, Laravel, Drupal, etc) and "legacy" code using superglobals without the need for an adapter.

Unlike Laravel and Symfony, WordPress doesn't support the worker mode of FrankenPHP (yet?), so there are not many benefits in terms of performance (except the ability to preload assets using 103 Early Hints, which can reduce the latency of a page load by 30%).

That being said, FrankenPHP makes it easy to enable HTTP cache with WordPress and simplifies the deployment story. There is a dedicated project for WordPress and FrankenPHP, that comes with a built-in HTTP cache tailored for WordPress (using the Souin Go library): https://github.com/StephenMiracle/frankenwp

Hi,

FrankenPHP author here. We would very much appreciate a reproducer. According to most benchmarks, FrankenPHP is generally much faster (~3 times) than FPM when worker mode is enabled, but there are still some outliers, and we're working with PHP maintainers to fix them.

I maintain the Mercure protocol (built on SSE) and the reference implementation (written in Go, available as a standalone binary and a Caddy module) which does exactly that: https://mercure.rocks

In addition to the free and open source server, we also provide a cloud offering and on-premises versions that support clustering using Redis Streams, Kafka, Pulsar or Postgres LISTEN/NOTIFY as backends.

The solution is used by many big actors in production for years:

How Raven Controls uses Mercure to power big events such as Cop 21 and Euro 2020: https://api-platform.com/con/2022/conferences/real-time-and-...

Pushing 8 million Mercure notifications per day to run mail.tm: https://les-tilleuls.coop/en/blog/mail-tm-mercure-rocks-and-...

100,000 simultaneous Mercure users to power iGraal: https://speakerdeck.com/dunglas/mercure-real-time-for-php-ma...

The approach isn't the same:

Roadrunner executes php-cli and connects it to its web server through GRPC; FrankenPHP uses an ad-hoc SAPI, it is more like Apache's mod_php, the Go code uses the PHP interpreter as a library, it's all in the same process.

RoadRunner only has a worker mode, and can only work with compatible apps; FrankenPHP has a "standard" mode compatible with all existing applications, and a worker mode that requires some code changes (like RR).

RoadRunner runner uses PSR-7 HTTP messages; FrankenPHP uses plain old superglobals and streams (both in normal and in worker modes), they are reset after each handled request.

RoadRunner is battle-tested and production ready; FrankenPHP is experimental and not yet ready for production use.

FrankenPHP can also be used as a Go library to integrate PHP into any Go program or server (theoretically, it should be possible to integrate FrankenPHP into Traefik or the local Symfony web server, which are written in Go).

API Platform is a popular and easy to use semantic web framework:

1. You design your data model as a set of PHP classes, or you generate the class from any RDF vocabulary such as Schema.org

2. API Platform uses the classes to expose a JSON-LD API with with all the typical features (sorting, filtering, pagination…)

3. You use the provided "smart clients" to build a dynamic admin interface or to scaffold Next, Nuxt or React Native apps (these tools rely on the Hydra API description vocabulary, and work with any Hydra-enabled API)

In addition to RDF/JSON-LD/Hydra, API Platform also supports ActivityPub.

https://api-platform.com

While it looks great, this app isn’t open-source.

Open-source means that the source code can be freely modified and redistributed. This is explicitly forbidden by the license of Amplosion. The proper term for this kind of licence is “source-available”. The description and the website are misleading and should be updated.

A "collaboration" led by Jan Jambon, the guy who says that about collaborating with the Nazis:

"The people who collaborated with the Germans had their reasons. Me, I was not alive during that time."

I don’t trust GAFAM to protect my privacy, but I wouldn’t trust this government either.

Hi, and thanks for the feedback.

I'm aware of this "issue" (I must mention it in the repo, and I will). However, I don't think that it matters much for a web API: in most cases, inside web browsers, the TCP connection will already be "warmed" when the browser will send the first (and subsequent) requests to the API, because the browser will have loaded the HTML page, the JS code etc, usually from the same origin. And even if it isn't the case (mobile apps, API served from a third-party origin...) only the firsts requests will have to "warm" the connection (it doesn't matter if you use compound or atomic documents then), all subsequent requests, during the lifetime of the TCP connection, will use a "warmed" connection.

Or am I missing something?

Anyway, a PR to improve this benchmark (which aims at measuring the difference - if any - between serving atomic documents vs serving compound documents in real-life use cases) and show all cases will be very welcome!