Re: RFC proposal: worker mode primitives for SAPIs
| From: | Larry Garfield | Date: | Sat, 30 Dec 2023 19:48:39 +0000 |
| Subject: | Re: RFC proposal: worker mode primitives for SAPIs | ||
| References: | 1 2 3 4 5 6 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-122073@lists.php.net to get a copy of this message | ||
On Sat, Dec 30, 2023, at 4:53 AM, Rowan Tommins wrote:
> On 30 December 2023 09:59:07 GMT, Robert Landers
> <landers.robert@gmail.com> wrote:
>>For this to happen in PHP Core, there would need to be request objects
>>instead of a global state.
>
> Again, the representation as objects isn't a key requirement. Python's
> WSGI spec simply has a dictionary (read: associative array) of the
> environment based on CGI. The application might well turn that into a
> more powerful object, but standardisation of such wasn't considered a
> pre-requisite, and would actually have hampered ASGI, where not all
> events represent an HTTP request.
>
> The key requirement is that you have some way of passing the current
> request and response around as scoped variables, not global state.
> That's essential for any kind of concurrent run-time (async,
> thread-aware, etc).
>
> An event / subscriber model fits well with that: the local scope for
> each request is set up by an invocation of the callback with defined
> parameters and return value.
>
> Funnily enough, the example of a worker script for FrankenPHP does both
> things: it sends each request to the same application "handle"
> callback, passing in the super-global arrays as parameters to be used
> as non-global state.
> https://frankenphp.dev/docs/worker/#custom-apps So
> really all I'm arguing is that a few more lines of that PHP example be
> moved into the C implementation, so that the user only needs to provide
> that inner callable, not the outer while loop.
So you're suggesting something like:
$app->initializeStuffHowever();
set_event_handler(Closure $handler);
// Script blocks here until a sigkill is received, or something.
I think there's an important distinction that is getting missed in the above discussion, beyond
the push-vs-pull question. FrankenPHP, as I understand it, pre-boots multiple worker processes,
keeps them in memory, and then handles each request in its own process. Swoole, Amp/React/Revolt,
and friends have only a single process running at all, and make use of async to simulate multiple
simultaneous requests, a la NodeJs. That means mutable global variables in the FrankenPHP model
still won't leak between parallel requests, whereas they absolutely would/do in a Swole/Revolt
world.
I'm not going to call one of those better or worse (I don't have enough experience with
either to say), but they are different beasts for which first class support would be different SAPIs
either way. They're not mutually exclusive thanks to Fibers (which mean you don't need
the entire call stack to be async), but you would want to pick one or the other as primary runner
mode of an application. Let's keep that in mind when making comparisons.
The Franken-model is closer to how PHP-FPM works today, which means that is easier to port existing
code to, especially existing code that has lots of globals or hidden globals. (Eg, Laravel.) That
may or may not make it the better model overall, I don't know, but it's the more-similar
model.
All that said, the idea of allowing a "persistent HTTP handler process" SAPI,
"persistent Queue handler process" SAPI, and "persistent cron handler process"
SAPI (or whatever combination of persistent processes) to all run side by side with the same code
base but different entry point scripts is... Hot. If we can do something that would enable that
kind of runtime model, I am very much here for that.
--Larry Garfield