Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On Fri, Jan 5, 2024 at 9:40 AM Michał Marcin Brzuchalski < michal.brzuchal...@gmail.com> wrote: > There are indeed dozens of libraries already working with PSR nicely but > IMHO > the API should provide all the necessary information in a way that allows > the construction of such objects, > but suggesting PSR with request/response objects will limit the > capabilities of worker mode API > to handle pure HTTP protocol only. > > What I'd like to say is that I believe for the initial proposal of any > eventual worker mode API > with the PSR with request/response objects should not be considered at all. > > Cheers > I think it's been mentioned quite a few times that it doesn't matter what gets passed to the callable function that hands over control to userland, as long as it's more functional-style and not superglobals. I also think that there's merit in both sides of the conversation between PSR-7 vs associative arrays, but I find it more important to get one of them, any of them and not halt for one or the other. PSR would make it HTTP-only, yes, but that largely benefits the PHP ecosystem to an extent order of magnitude larger than any non-HTTP format. On the other hand, being a dynamically typed language, nothing holds us from having a more simple/generic `function handler(mixed $event)` format which can also be used to process HTTP and non-HTTP events. I do prefer the more generic one as I would be interested in seeing what PHP would become with the capability of processing non-HTTP protocols made easier. That being said, I find it important to consider the quality of such an API for its users. It would end up forcing users to do the following: ``` function handler(mixed $event) { if (isset($event['_REQUEST'])) { // We are on HTTP Protocol } if (isset($event['...'])) { // This is a Websocket } } ``` If the original proposal is correct and/or my little understanding of this thread is somewhat in the right direction, it means that the introduction of a PHP function that asks its engine for the next event to process isn't a huge amount of work on PHP Internals. If that's true, I would ask that we consider making something more flexible / forgiving of errors / adjustable and evolution-friendly. Instead of striving so much for coming up with one perfect API that shall be the one true API for PHP for the next decade, we can instead consider the possibility of having multiple small APIs that can harmonically coexist. Example: Classic: ``` $classicHttpHandler = function (array $get, array $post, array $request, array $server, array $cookies): string|Stringable { // process incoming request in a somewhat backward-compatible friendly way return 'http response'; // Return the response similarly to how we used to `echo` it to the server. } worker_http_classic($classicHttpHandler); ``` PSR-7: ``` $httpMiddlewareHandler = function (\Psr\Http\Message\RequestInterface $request): \Psr\Http\Message\ResponseInterface { // Process Request } worker_http_psr7($httpMiddlewareHandler); ``` HTTP Raw ``` $httpHandler = function (\Psr\Http\Message\StreamInterface $raw): \Psr\Http\Message\ResponseInterface { // Process Request } worker_http_raw($httpHandler); ``` STDIN ``` $stdinHandler = function (SomeStdinCompatibleType $stdin): SomeStdoutCompatibleType { } worker_stdin($stdinHandler); ``` Websocket ``` $websocketHandler = function (string $event, mixed $data): ??? { // Process websocket incoming event } worker_websocket_event($httpHandler); ``` These APIs don't need to be ready on day one. They don't even need to be ready at all, actually. Each would end up being its own RFC. What makes the system a bit more. flexible is the api naming which follows the pattern PHP Engine Namespace (worker), Purpose Namespace (_http, _websocket, etc) and Variation Namespace (_classic, _psr7, _raw). For me personally one awesome last step would make this a PHP Class instead of procedural functions. That would be even better because we could use the Class namespace itself to version it and provide future changes without breaking what's been introduced already. -- Marco Deleu
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On 5 January 2024 12:18:51 GMT, Robert Landers wrote: >This is easy to handle from C. If the callback takes an argument, >don't fill in the super-globals. Again, that's compatible only in a narrow sense: it provides both APIs on any run-time which can do so safely. You still have an incompatible upgrade to make though: if you write code today for FrankenPHP, and directly use the super-global arrays it populates, you cannot take that code tomorrow and use it in Swoole, which does not provide those super-globals. If you write code today which uses callback parameters, you can take that code and use it unmodified with any system which provides those parameters - including async implementations. All that's missing for that to happen right now is a standard format for those parameters. > It allows legacy apps to be slowly >"upgraded" while allowing newer apps to take full advantage of a SAPI. It's actually quite easy to add most of the backwards compatibility needed for legacy apps in userland, by populating the superglobals, and running an output buffer to capture echo etc into the response. > However, if we go into the design with the >concurrent server story in mind, I think we can create something much >better than what is available from FrankenPHP. Precisely. That's why I used the phrase "forwards compatibility" - I'm not saying php-src needs to support all of this right now, just that *the API design* should have an eye on the future, not just the past. Regards, -- Rowan Tommins [IMSoP] -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
pt., 5 sty 2024 o 13:19 Robert Landers napisał(a): > On Fri, Jan 5, 2024 at 11:59 AM Rowan Tommins > wrote: > > > > Globals is how this works (atm) > > > > It's how it works for native SAPIs. It's not, as far as I know, how any > worker system other than FrankenPHP has implemented its API. Every other > implementation I've seen, whether async or not, passes in some form of > request data to the callback, with the exception of RoadRunner, which gives > the data as a return value from a "get next request" function. > > Nearly every library in existence knows how to use these globals > (including 30 years old legacy code). There are also the unwieldy PSR > request/response containers for which there are dozens (if not > hundreds) of implementations. It would be fantastic if there were > already an extension-based implementation that could be adopted into > php-src; though I feel like that is a separate conversation. > There are indeed dozens of libraries already working with PSR nicely but IMHO the API should provide all the necessary information in a way that allows the construction of such objects, but suggesting PSR with request/response objects will limit the capabilities of worker mode API to handle pure HTTP protocol only. What I'd like to say is that I believe for the initial proposal of any eventual worker mode API with the PSR with request/response objects should not be considered at all. Cheers
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On Fri, Jan 5, 2024 at 11:59 AM Rowan Tommins wrote: > > On 5 January 2024 09:02:05 GMT, Robert Landers > wrote: > > I don't think they are fundamentally incompatible. If we look at > >FrankenPHP's implementation, you pass a callback that gets called when > >there is a request. > > No, you pass a callback which is called exactly once, for the next request. > You have to implement your own loop if you want to handle multiple requests, > which obviously isn't how it would work with an async event loop. > > That was one of my suggested changes: move the loop into C, so that the API > was "callback called for each request". This actually *adds* flexibility on > the server end, to decide how often to call that callback, do so > asynchronously, etc. I think the goal here is to provide the basic building block: a function that takes a callable that, when called, blocks the script. Even when you have an event loop, there is some point when you call something and enter an infinite loop (the event loop), and no more of that file will be called ($app->start() or whatever). This is _that function_ for all intents and purposes. You can implement your own event-loop using do/while (such as in FrankenPHP), or a SAPI can call it in a loop for you. The bedrock is in core PHP, providing a standardized way of setting this up ... obviously, there are also SAPIs out there doing their own thing, and there always will be. > > Globals is how this works (atm) > > It's how it works for native SAPIs. It's not, as far as I know, how any > worker system other than FrankenPHP has implemented its API. Every other > implementation I've seen, whether async or not, passes in some form of > request data to the callback, with the exception of RoadRunner, which gives > the data as a return value from a "get next request" function. Nearly every library in existence knows how to use these globals (including 30 years old legacy code). There are also the unwieldy PSR request/response containers for which there are dozens (if not hundreds) of implementations. It would be fantastic if there were already an extension-based implementation that could be adopted into php-src; though I feel like that is a separate conversation. > So, the second suggested change is to standardise on the most common pattern > of passing parameters to a callback, rather than the unusual one of > populating and clearing superglobals. As a bonus, this pattern works with > both non-async and async workers. > > > > changing the signature of the callback is generally backwards compatible > > This is true in the narrow sense that it won't cause any fatal errors. But if > you write your application assuming that it will run in an environment where > globals are populated for you, it will not run in an environment which no > longer populates those globals. This is easy to handle from C. If the callback takes an argument, don't fill in the super-globals. It allows legacy apps to be slowly "upgraded" while allowing newer apps to take full advantage of a SAPI. That's how I would implement it, anyway. There is also something to be said to go "all the way" and just abandoning legacy apps, but that doesn't feel like something PHP would do. > >Changing the underlying implementation in php-src when there are > >native fibers/event loops probably won't even change anything (since > >that was exactly how they were designed). > > Sounds great! So we don't need to wait to put that implementation in place > then. > > > > >But holding up the entire conversation ... > > There is no reason whatsoever to hold anything up. The suggestion is not > "don't implement any worker API until we have an async implementation", it's > "a worker API sounds great, let's implement one that looks like this". > > Yes, it might take slightly longer to define some new array structures, but > we're talking about a few hours work to give us a much more flexible system, > not weeks of complex engineering. > > If the proposal is "copy some code from FrankenPHP into php-src, which nobody > else will want to use", it's pointless; if it's "standardise an API with some > enabling code", then *of course* we want to spend a bit of time designing > that API. That's fair. I was taking this push-back from you and others as, "No, we don't want this unless we can have all these other things," so thank you for clarifying that. I can largely agree -- I use amphp + fibers extensively in another project, so seeing more love for concurrent servers would be nice. Maybe I saw it that way because I have a fairly deep understanding of the shortcomings with fibers/async-php and see the amount of work required to support what you are proposing. However, if we go into the design with the concurrent server story in mind, I think we can create something much better than what is available from FrankenPHP. > Regards, > > -- > Rowan Tommins > [IMSoP] > > -- > PHP Internals - PHP Runtime Development Mailing List >
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On 5 January 2024 09:02:05 GMT, Robert Landers wrote: > I don't think they are fundamentally incompatible. If we look at >FrankenPHP's implementation, you pass a callback that gets called when >there is a request. No, you pass a callback which is called exactly once, for the next request. You have to implement your own loop if you want to handle multiple requests, which obviously isn't how it would work with an async event loop. That was one of my suggested changes: move the loop into C, so that the API was "callback called for each request". This actually *adds* flexibility on the server end, to decide how often to call that callback, do so asynchronously, etc. > Globals is how this works (atm) It's how it works for native SAPIs. It's not, as far as I know, how any worker system other than FrankenPHP has implemented its API. Every other implementation I've seen, whether async or not, passes in some form of request data to the callback, with the exception of RoadRunner, which gives the data as a return value from a "get next request" function. So, the second suggested change is to standardise on the most common pattern of passing parameters to a callback, rather than the unusual one of populating and clearing superglobals. As a bonus, this pattern works with both non-async and async workers. > changing the signature of the callback is generally backwards compatible This is true in the narrow sense that it won't cause any fatal errors. But if you write your application assuming that it will run in an environment where globals are populated for you, it will not run in an environment which no longer populates those globals. >Changing the underlying implementation in php-src when there are >native fibers/event loops probably won't even change anything (since >that was exactly how they were designed). Sounds great! So we don't need to wait to put that implementation in place then. >But holding up the entire conversation ... There is no reason whatsoever to hold anything up. The suggestion is not "don't implement any worker API until we have an async implementation", it's "a worker API sounds great, let's implement one that looks like this". Yes, it might take slightly longer to define some new array structures, but we're talking about a few hours work to give us a much more flexible system, not weeks of complex engineering. If the proposal is "copy some code from FrankenPHP into php-src, which nobody else will want to use", it's pointless; if it's "standardise an API with some enabling code", then *of course* we want to spend a bit of time designing that API. Regards, -- Rowan Tommins [IMSoP] -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
Hi, > But holding up the entire conversation because these things don't even > exist, BTW, I'm not asking to wait for the implementation of a native event loop before implementing a worker mode, I'm asking to design the worker mode API in a way that is compatible with an eventual native event loop (that I hope will eventually get merged into php, as the current status quo of blocking STL I/O is definitely not ideal for a programming language in 2024). Using superglobals for request information is already using a wrong approach in sight of native async, and while technically this is not completely incompatible with fibers, as superglobals can simply be copied immediately as soon a fiber is started, the same cannot be said for php://output and php://input streams, which cannot be copied in any way. I ask to completely avoid altering superglobals and other global state such as the php://input/output streams, and instead directly pass/return an array/object (it really does not matter to me if it's a PSR-7 RequestInterface or an array containing _GET, _POST, input, output keys, or anything else as long as superglobals and global state is not touched in any way). Backwards compatibility for code using superglobals is really a non-issue here, as worker mode in itself is already potentially NOT automatically backwards-compatible with legacy code, since applications running in worler mode have to deal with the fact that the global state is not reset at the end of each request. This in itself is not an issue as mentioned before, thanks to work inside of major PHP frameworks to better support worker mode, I.e. laravel octane, but since the beneficiaries of worker mode will mostly be modern frameworks and most legacy code will already require changes to better support it, using a new API with a standalone request object/array instead of superglobals is not a real issue. Regards, Daniil Gentili.
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On Fri, Jan 5, 2024 at 8:47 AM Rowan Tommins wrote: > > On 5 January 2024 06:55:34 GMT, Robert Landers > wrote: > > >I already said this, but to reiterate: I, personally, hear what you > >are saying and largely agree with you; however, before we can really > >have any kind of discussion on concurrent servers, we HAVE to address > >the underlying issues that are missing from PHP. In PHP-src > > So, let's address them... > > > > there are no such things as request objects > > This is a non-issue. As has been discussed already, it's perfectly fine to > have an event-based system where the event details are an associative array, > rather than a rich object. > > > > > There are no such things as event loops. There are fibers, > > but absolutely no std-library i/o functions are using them > > This is what the bulk of Daniil's email is suggesting a way to improve. > > > >We have a long way to go before those will be real things that we can > >have a proper conversation about in the context of php-src. > > If we keep waiting to have the conversation, it will never happen. > > And if we start building brand new APIs like infrastructure for worker-mode > SAPIs, in ways that are fundamentally incompatible with async, we're just > making more work for ourselves when we do get there. I don't think they are fundamentally incompatible. If we look at FrankenPHP's implementation, you pass a callback that gets called when there is a request. This is the same as giving Swoole a callback to call when a request is received, though the underlying implementation might be very different. An event-loop doesn't matter here and what gets passed to the callback is what we are discussing here. The exact implementation (in php-src) matters, but only so far as what php-src is capable of. Globals is how this works (atm) and changing the signature of the callback is generally backwards compatible. For example, if we start with only globals (no parameters), adding parameters later once there are request objects/arrays/whatever, is fine. Calling a callback with parameters when the function actually doesn't accept any arguments, isn't even a notice (https://3v4l.org/URj9b). Changing the underlying implementation in php-src when there are native fibers/event loops probably won't even change anything (since that was exactly how they were designed). But holding up the entire conversation because these things don't even exist, seems like a pointless endeavor since they may not even pass the RFC point (IIRC, getting an event-loop in PHP was a large part of the reason fibers are the way they are because people were against an event-loop at that time). > Regards, > > -- > Rowan Tommins > [IMSoP] > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php > Robert Landers Software Engineer Utrecht NL -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On 5 January 2024 06:55:34 GMT, Robert Landers wrote: >I already said this, but to reiterate: I, personally, hear what you >are saying and largely agree with you; however, before we can really >have any kind of discussion on concurrent servers, we HAVE to address >the underlying issues that are missing from PHP. In PHP-src So, let's address them... > there are no such things as request objects This is a non-issue. As has been discussed already, it's perfectly fine to have an event-based system where the event details are an associative array, rather than a rich object. > There are no such things as event loops. There are fibers, > but absolutely no std-library i/o functions are using them This is what the bulk of Daniil's email is suggesting a way to improve. >We have a long way to go before those will be real things that we can >have a proper conversation about in the context of php-src. If we keep waiting to have the conversation, it will never happen. And if we start building brand new APIs like infrastructure for worker-mode SAPIs, in ways that are fundamentally incompatible with async, we're just making more work for ourselves when we do get there. Regards, -- Rowan Tommins [IMSoP] -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On Fri, Jan 5, 2024 at 2:56 AM Daniil Gentili wrote: > > Hi, > > I've been lurking around in the discussion for a while, and I'd like to chime > in now since the main, glaring issue with this proposal has only been > explicitly mentioned by Rowan Tomminis, with that subthread quickly > degenerating with misguided replies. > > PHP as a language absolutely needs a persistent worker mode like in all other > backend languages, which will greatly improve performance by avoiding all > overhead related to request initialization. > > However, the current proposal of adding support for worker mode SAPIs based > on the usual PHP superglobals is fundamentally incompatible with concurrency > (aka async, aka swoole, amphp, fiber-based concurrent runtimes in general), > and I believe would steer the PHP ecosystem in the wrong direction. > > Rowan already offered a nice example of why earlier in the thread, but as an > explanation to those that may not have understood that, so I whipped up a > briefer at https://gist.github.com/danog/f0e9103e6a7e1bcec1b92c411a3c4607 > > > > So no, unlike what I've read in another message here, "The nodejs curse [...] > where async and co may actually slow down your whole node." is simply false > for the majority of modern usecases, because the majority of modern > applications is I/O-intensive, not CPU-intensive. > > > Implementing a worker API the way it is proposed is fundamentally > incompatible with userland cooperative schedulers aka event loops like amphp > or reactphp, and each request would be handled, just like in php-fpm, in a > separate OS thread, not in a much more efficient userland thread. > > Cooperative schedulers implemented outside of PHP in the form of an extension > such as swoole would also not be able to easily make use of the initially > proposed API to handle requests in separate coroutines, even if the > handle_request function was intercepted by swoole to return control to the > swoole event loop (which would already make it superfluous as a PHP API), > since the proposal involves messing around with the usual superglobals, which > as mentioned by Rowan would require manual copying of the superglobals before > using them in a newly spawned swoole coroutine. > > I believe that a much, much better way of implementing a worker mode in PHP > core would be to provide a fiber-aware function/static method returning, upon > receiving a request, a class implementing the PSR-7 RequestInterface. > > Fiber-aware here means that the function should behave in a way similar to > how all native PHP I/O functions should behave in an upcoming Native Event > Loop RFC I'm planning to make. > > The idea here is to make all I/O related functions, including this new > wait_request function, completely async in a manner that is compatible with > fibers and pure PHP event loops like amphp. > > It would essentially work as follows: an event loop like uv is integrated > within PHP itself at least for the native stream wrapper (I.e. all filesystem > and network functions, file_get_contents and so on). > Extensions will be provided an API to interact with the event loop. > > I'm currently finalizing the details, and might probably make a first RFC in > the coming weeks, suffice to say that everything will work in a manner very > similar to how async works in both the ext-pq and php-tokio extensions, > albeit with fiber integration: a separate event loop (let's call it native) > is started in another OS thread (like with ext-pq or php-tokio, WITHOUT the > need for ZTS, as no PHP data structures are modified in the native event > loop), events are sent via a single descriptor from the native event loop to > the userland event loop (I.e. amphp). > > If running inside a fiber, tasks are queued to the native event loop and the > fiber is suspended with a NativeSuspension, then resumed by the userland > event loop. > > If not running inside a fiber, tasks are queued to the native event loop and > control is returned to the userland event loop. > > Essentially, my proposal is almost exactly what is already being done in > https://github.com/danog/php-tokio, but library-agonstic and implemented > inside of PHP itself, perhaps even using Rust and tokio as well. > > I feel that the current direction of the discussion of PHP worker modes is > wrong, as it is mostly ignoring the presence of a perfectly usable > concurrency API in PHP (fibers): this has potential to cause a big split in > the PHP ecosystem, unless PHP finally fully embraces concurrency and async > with a native event loop proposal, like the one I intend to present soon. > > I hope that further discussion of a worker mode continues with an eye to the > future with native concurrency :) > > Regards, > Daniil Gentili. > > P. S. Just in case to avoid confusion for some, frankenphp does NOT add > native concurrency to php using goroutines, as control to the go event loop > is only returned
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
Hi, I've been lurking around in the discussion for a while, and I'd like to chime in now since the main, glaring issue with this proposal has only been explicitly mentioned by Rowan Tomminis, with that subthread quickly degenerating with misguided replies. PHP as a language absolutely needs a persistent worker mode like in all other backend languages, which will greatly improve performance by avoiding all overhead related to request initialization. However, the current proposal of adding support for worker mode SAPIs based on the usual PHP superglobals is fundamentally incompatible with concurrency (aka async, aka swoole, amphp, fiber-based concurrent runtimes in general), and I believe would steer the PHP ecosystem in the wrong direction. Rowan already offered a nice example of why earlier in the thread, but as an explanation to those that may not have understood that, so I whipped up a briefer at https://gist.github.com/danog/f0e9103e6a7e1bcec1b92c411a3c4607 So no, unlike what I've read in another message here, "The nodejs curse [...] where async and co may actually slow down your whole node." is simply false for the majority of modern usecases, because the majority of modern applications is I/O-intensive, not CPU-intensive. Implementing a worker API the way it is proposed is fundamentally incompatible with userland cooperative schedulers aka event loops like amphp or reactphp, and each request would be handled, just like in php-fpm, in a separate OS thread, not in a much more efficient userland thread. Cooperative schedulers implemented outside of PHP in the form of an extension such as swoole would also not be able to easily make use of the initially proposed API to handle requests in separate coroutines, even if the handle_request function was intercepted by swoole to return control to the swoole event loop (which would already make it superfluous as a PHP API), since the proposal involves messing around with the usual superglobals, which as mentioned by Rowan would require manual copying of the superglobals before using them in a newly spawned swoole coroutine. I believe that a much, much better way of implementing a worker mode in PHP core would be to provide a fiber-aware function/static method returning, upon receiving a request, a class implementing the PSR-7 RequestInterface. Fiber-aware here means that the function should behave in a way similar to how all native PHP I/O functions should behave in an upcoming Native Event Loop RFC I'm planning to make. The idea here is to make all I/O related functions, including this new wait_request function, completely async in a manner that is compatible with fibers and pure PHP event loops like amphp. It would essentially work as follows: an event loop like uv is integrated within PHP itself at least for the native stream wrapper (I.e. all filesystem and network functions, file_get_contents and so on). Extensions will be provided an API to interact with the event loop. I'm currently finalizing the details, and might probably make a first RFC in the coming weeks, suffice to say that everything will work in a manner very similar to how async works in both the ext-pq and php-tokio extensions, albeit with fiber integration: a separate event loop (let's call it native) is started in another OS thread (like with ext-pq or php-tokio, WITHOUT the need for ZTS, as no PHP data structures are modified in the native event loop), events are sent via a single descriptor from the native event loop to the userland event loop (I.e. amphp). If running inside a fiber, tasks are queued to the native event loop and the fiber is suspended with a NativeSuspension, then resumed by the userland event loop. If not running inside a fiber, tasks are queued to the native event loop and control is returned to the userland event loop. Essentially, my proposal is almost exactly what is already being done in https://github.com/danog/php-tokio, but library-agonstic and implemented inside of PHP itself, perhaps even using Rust and tokio as well. I feel that the current direction of the discussion of PHP worker modes is wrong, as it is mostly ignoring the presence of a perfectly usable concurrency API in PHP (fibers): this has potential to cause a big split in the PHP ecosystem, unless PHP finally fully embraces concurrency and async with a native event loop proposal, like the one I intend to present soon. I hope that further discussion of a worker mode continues with an eye to the future with native concurrency :) Regards, Daniil Gentili. P. S. Just in case to avoid confusion for some, frankenphp does NOT add native concurrency to php using goroutines, as control to the go event loop is only returned when calling functions like header or echo which cause a suspension of the goroutine because an I/O operation is made on the go side, but 1) That's incompatible with fibers, and not just because of the minor go
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On Tue, Jan 2, 2024 at 3:46 PM Jeffrey Dafoe wrote: > > > 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. > > Jumping in to add that NGINX has their newish Unit app server, which uses > Yet Another Custom SAPI for PHP. > > It seems to me that its development significantly decreased after F5 takeover and the unit main developer leaving the company so not sure if there is that much future in it. Cheers Jakub
RE: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
> > 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. Jumping in to add that NGINX has their newish Unit app server, which uses Yet Another Custom SAPI for PHP. -Jeff -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
I'm running out of different ways to say the same thing, and not really sure which part of my previous messages people haven't understood. I'm really not saying anything very controversial or complicated, just "had you considered that style B would offer these additional possibilities over style A". So I'm going to quote the parts of previous messages which I think already answer the latest questions. After that, I'm going to leave the thread to others for a bit, unless I see a question that isn't just retreading the same ground. On 01/01/2024 17:36, Pierre Joye wrote: Unless I misunderstand the current proposal, it is about providing a core interface to allow one to create its own SAPI similar to FrankenPHP, which does not handle request in a singe thread but a thread pool handled by go's coroutine. From Kévin's opening post: In addition to FrankenPHP, projects such as RoadRunner and Swoole provide engines supporting worker modes. [...] the existence of a common infrastructure would standardize the way worker scripts are created and provide a high-level PHP API for writing worker scripts that work with all SAPIs that rely on this new feature. From my last message: If we're attempting to standardise a new API for worker modes (i.e. HTTP servers which are no longer "shared nothing"), choosing one which can be used by consecutive worker modes (FrankenPHP , RoadRunner) but not concurrent ones (Swoole, ReactPHP, AMPHP) feels like a big missed opportunity. On 01/01/2024 17:40, Robert Landers wrote: I'm not sure concurrent servers would even be able to be in scope if we wanted them to be? From my message dated 2023-12-29 22:55 UTC: Note that both async and WebSockets were mentioned as possible "forward compatibility". If we're talking about "next generation SAPIs", these are the kinds of features that people will be - and already are - developing; so it seems foolish not to at least consider them when designing new baseline APIs. On 01/01/2024 17:36, Pierre Joye wrote: It is a first step and based on the usages/feedback, the next steps could be the second part of your comment. Or? From my message dated 2023-12-31 01:20 UTC: if you standardise on an API that populates global state, you close off any possibility of using that API in a concurrent environment. If you instead standardise on callbacks which hold request and response information in their own scope, you don't close anything off. And from 2023-12-30 10:53 UTC: 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). Regards, -- Rowan Tommins [IMSoP]
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On Mon, Jan 1, 2024 at 12:18 PM Rowan Tommins wrote: > > On 31 December 2023 16:31:31 GMT, Pierre Joye wrote: > > >php handles this in threadsafe mode > > Depending on your exact definition of "php", this is either irrelevant or > just plain wrong. > > If you mean "the HTTP SAPIs shipped with official builds of PHP", then it's > true, none handle multiple concurrent requests in a single thread using async > I/O. But none handle multiple consecutive requests in a single thread using a > "worker mode" either, which is the whole point of this conversation. > > If you mean for "php" to include third party HTTP handlers such as > FrankenPHP, then it also includes Swoole, which is what I was describing. > Please someone correct me if I'm wrong, but I understand ReactPHP and AMPHP > also include HTTP servers using the same principle. > > So, to reiterate my point once more: implementations of PHP using async > concurrency are out there already in production use. If we're attempting to > standardise a new API for worker modes (i.e. HTTP servers which are no longer > "shared nothing"), choosing one which can be used by consecutive worker modes > (FrankenPHP , RoadRunner) but not concurrent ones (Swoole, ReactPHP, AMPHP) > feels like a big missed opportunity. > > Regards, > > -- > Rowan Tommins > [IMSoP] > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php > Hey Rowan, I'm not sure concurrent servers would even be able to be in scope if we wanted them to be? PHP doesn't have an "event-loop", concurrent i/o, or any building blocks needed to serve concurrent requests. It's been made possible through extensions and libraries that aren't maintained by PHP, so I'm not sure how we'd support them directly without those other basic functionalities. If we directly wanted to support concurrent servers, I think there is probably a lot of work to do at a very low level before we could realistically include them in this part of the conversation. Robert Landers Software Engineer Utrecht NL -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On Mon, Jan 1, 2024, 6:18 PM Rowan Tommins wrote: > On 31 December 2023 16:31:31 GMT, Pierre Joye > wrote: > > >php handles this in threadsafe mode > > Depending on your exact definition of "php", this is either irrelevant or > just plain wrong. > > If you mean "the HTTP SAPIs shipped with official builds of PHP", then > it's true, none handle multiple concurrent requests in a single thread > using async I/O. But none handle multiple consecutive requests in a single > thread using a "worker mode" either, which is the whole point of this > conversation. > Unless I misunderstand the current proposal, it is about providing a core interface to allow one to create its own SAPI similar to FrankenPHP, which does not handle request in a singe thread but a thread pool handled by go's coroutine. I can imagine other developers implement it using other mechanisms (rust or c++ f.e.) but the main interface from a php internal pov remains. It is a first step and based on the usages/feedback, the next steps could be the second part of your comment. Or? best, Pierre >
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On 31 December 2023 16:31:31 GMT, Pierre Joye wrote: >php handles this in threadsafe mode Depending on your exact definition of "php", this is either irrelevant or just plain wrong. If you mean "the HTTP SAPIs shipped with official builds of PHP", then it's true, none handle multiple concurrent requests in a single thread using async I/O. But none handle multiple consecutive requests in a single thread using a "worker mode" either, which is the whole point of this conversation. If you mean for "php" to include third party HTTP handlers such as FrankenPHP, then it also includes Swoole, which is what I was describing. Please someone correct me if I'm wrong, but I understand ReactPHP and AMPHP also include HTTP servers using the same principle. So, to reiterate my point once more: implementations of PHP using async concurrency are out there already in production use. If we're attempting to standardise a new API for worker modes (i.e. HTTP servers which are no longer "shared nothing"), choosing one which can be used by consecutive worker modes (FrankenPHP , RoadRunner) but not concurrent ones (Swoole, ReactPHP, AMPHP) feels like a big missed opportunity. Regards, -- Rowan Tommins [IMSoP] -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
hello, On Sun, Dec 31, 2023, 6:59 PM Rowan Tommins wrote: Then one of us is missing something very fundamental. As I understand it, > Swoole's model is similar to that popularised by node.js: a single thread > processes multiple incoming requests concurrently, using asynchronous I/O. The nodejs curse yes, where async and co may actually slow down your whole node. DB result > 09 Request A formats and returns response > 10 Request A complete > 11 Request B resumed > 12 Request B fornats and returns response > php handles this in threadsafe mode, like modphp f.e. It is why frankenphp requires a TS build of php. Requests are handled by a thread pool, not in single thread event loop which may block all requests. best, Pierre
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On 31 December 2023 08:31:16 GMT, "Kévin Dunglas" wrote: >This new function is intended for SAPIs. Swoole was given as an example of >worker mode, but it isn't a SAPI. AFAIK, it doesn't use the SAPI >infrastructure provided by PHP. >The scope of my proposal is only to provide a new feature in the SAPI >infrastructure to build worker modes to handle HTTP requests, not to deal >with non-SAPI engines. One of the advantages you suggested of your proposal is that users would have a consistent way to write worker scripts. To achieve that, you want a *design* that can be adopted by as many implementations as possible, regardless of how they implement it. Providing helper infrastructure for that design is a secondary concern - as you admit, the actual code you're proposing to add is quite short. >That being said, I don't understand what would prevent Swoole from >implementing the proposed API Then one of us is missing something very fundamental. As I understand it, Swoole's model is similar to that popularised by node.js: a single thread processes multiple incoming requests concurrently, using asynchronous I/O. For instance, a thread might run the following: 01 Request A received 02 Request A input validated 03 Request A sends async query to DB 04 Request A hands control to event loop while it awaits result 05 Request B received 06 Request B sends async HTTP call to some API 07 Request B awaits result 08 Request A resumed with DB result 09 Request A formats and returns response 10 Request A complete 11 Request B resumed 12 Request B fornats and returns response Each request has its own call stack, started by a different call to the registered event handler, but any global state is shared between them - there is no actual threading going on, so no partitioned memory. If requests are communicated by setting up superglobals, that will happen at step 01 and again at step 05. If you try to read from them at step 09, you would see them populated with information about request B, but you're trying to handle request A. It would be possible to work around that by placing large warnings to users not to read superglobals after any async call - basically forcing them to create scoped copies to pass around. But the worse problem is output: if step 09 and step 12 both just use "echo", how do you track which output needs to go to which network connection? You can't just set up an output buffer, because that's global state shared by both call stacks. You have to put *something* into the scope of the call stack - a callback to write output, an expected return value, etc. Asynchronous code ends up somewhat resembling functional programming: everything you want to have side effects on needs to be passed around as parameters and return values, because the only thing isolated between requests is local variable scope. Regards, -- Rowan Tommins [IMSoP] -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On Sun, Dec 31, 2023 at 2:20 AM Rowan Tommins wrote: > On 30 December 2023 19:48:39 GMT, Larry Garfield > wrote: > >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. > > That's why I said earlier that it provides better backwards compatibility > - existing code which directly uses PHP's current global state can more > easily be run in a worker which populates that global state. > > However, the benefit is marginal, for two reasons. Firstly, because in > practice a lot of applications avoid touching the global state outside of > some request bootstrapping code anyway. The FrankenPHP example code and > Laravel Octane both demonstrate this. > > Secondly, because in an environment that handles a single request at a > time, the reverse is also possible: if the server passes request > information directly to a callback, that callback can populate the > superglobals as appropriate. The only caveat I can think of is input > streams, since userland code can't reset and populate php://input, or > repoint STDOUT. > > On the other hand, as soon as you have any form of concurrency, the two > models are not interchangeable - it would make no sense for an asynchronous > callback to read from or write to global state. > > And that's what I meant about FrankenPHP's API having poor forward > compatibility - if you standardise on an API that populates global state, > you close off any possibility of using that API in a concurrent > environment. If you instead standardise on callbacks which hold request and > response information in their own scope, you don't close anything off. > > If anything, calling this "forwards compatibility" is overly generous: the > OP gave Swoole as an example of an existing worker environment, but I can't > see any way that Swoole could implement an API that communicated request > and response information via global state. > > Regards, > > -- > Rowan Tommins > [IMSoP] > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php This new function is intended for SAPIs. Swoole was given as an example of worker mode, but it isn't a SAPI. AFAIK, it doesn't use the SAPI infrastructure provided by PHP. The scope of my proposal is only to provide a new feature in the SAPI infrastructure to build worker modes to handle HTTP requests, not to deal with non-SAPI engines. That being said, I don't understand what would prevent Swoole from implementing the proposed API, or even to implement a userland implementation of the proposed API using Swoole under the hood. It seems doable to emulate the sequential request handling and to create an adapter from their custom objects to superglobals and streams. For WebSockets and WebTransports, the same considerations apply. The SAPI API will have to be extended to deal with such low-level network layers, worker mode or not. To me, this is very interesting (and needed) but should be discussed in another RFC. As pointed out by Crell, FrankenPHP (and similar theoretical solutions) starts as many workers as needed. This can be a fixed set of workers, as in FrankenPHP, or a dynamic number of workers, similar to traditional FPM workers. FrankenPHP uses threads to parallelize request handling (to start several instances of the worker script in parallel). Other techniques could be used, for instance, in the future, we could use goroutines (which use a mix of system threads and async IO, and goroutines are handled in a single system thread: https://github.com/golang/go/blob/master/src/runtime/HACKING.md#gs-ms-ps) instead of threads, by adding a new backend to TSRM. The global state is never reset in the same worker context, it is preserved across requests, except for superglobals and streams, which are updated with the data of the request being handled. Superglobals are the PHP way to expose CGI-like data. Adding support for other ways to do it such as proposed by WSGI, and/or new objects and the like could be interesting, but again this isn't the scope of this proposal which is narrow, and tries to reuse the existing infrastructure as much as possible. The proposal is simple enough to support new ways if introduced at some point in PHP, and the Symfony Runtime and Laravel Octane libraries prove that it's possible to implement more advanced data structures user-land on top of the existing superglobals infrastructure. Regarding the infinite loop, we could indeed remove it using a few lines of code. I hesitated to do that initially, but the loop gives more flexibility by allowing the implementation of many features in user-land (like restarting the worker after a fixed number of requests, when the memory reaches a certain level, etc). Without this loop, all these
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On 30 December 2023 19:48:39 GMT, Larry Garfield wrote: >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. That's why I said earlier that it provides better backwards compatibility - existing code which directly uses PHP's current global state can more easily be run in a worker which populates that global state. However, the benefit is marginal, for two reasons. Firstly, because in practice a lot of applications avoid touching the global state outside of some request bootstrapping code anyway. The FrankenPHP example code and Laravel Octane both demonstrate this. Secondly, because in an environment that handles a single request at a time, the reverse is also possible: if the server passes request information directly to a callback, that callback can populate the superglobals as appropriate. The only caveat I can think of is input streams, since userland code can't reset and populate php://input, or repoint STDOUT. On the other hand, as soon as you have any form of concurrency, the two models are not interchangeable - it would make no sense for an asynchronous callback to read from or write to global state. And that's what I meant about FrankenPHP's API having poor forward compatibility - if you standardise on an API that populates global state, you close off any possibility of using that API in a concurrent environment. If you instead standardise on callbacks which hold request and response information in their own scope, you don't close anything off. If anything, calling this "forwards compatibility" is overly generous: the OP gave Swoole as an example of an existing worker environment, but I can't see any way that Swoole could implement an API that communicated request and response information via global state. Regards, -- Rowan Tommins [IMSoP] -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
Hi Larry, sob., 30 gru 2023 o 20:49 Larry Garfield napisał(a): > On Sat, Dec 30, 2023, at 4:53 AM, Rowan Tommins wrote: > > On 30 December 2023 09:59:07 GMT, Robert Landers > > 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. > What you wrote sounds like some good points (as usual). I'm not an expert (yet!) but was playing around with some callable trying to mimic ASGI https://github.com/brzuchal/asgi-playground/blob/main/app.php#L26-L37 What I think currently (maybe too hurry, but...) is that this kind of approach is flexible enough to handle in easy way many SAPIs which identify to app their capabilities, and the app decides how and what can handle `$scope['type']` in the example code. I know there is a Runtime library, that tries to integrate Symfony/Laaravel to many SAPIs, but as far as I understood the discussion went to figure out if there is some kind of standard approach that could be shaped under the PHP umbrella. Maybe this is just a temporary fascination about ASGI solution, could be. If this is not in the scope of interest of anyone then forgive me, I won't bother anymore. Cheers, -- Michał Marcin Brzuchalski
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On Sat, Dec 30, 2023, at 4:53 AM, Rowan Tommins wrote: > On 30 December 2023 09:59:07 GMT, Robert Landers > 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 -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On 30 December 2023 09:59:07 GMT, Robert Landers 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. Regards, -- Rowan Tommins [IMSoP] -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
Hi Robert, sob., 30 gru 2023, 10:59 użytkownik Robert Landers napisał: > > > - FrankenPHP expects the user to manage the main event loop ... > > > > > > > > > This isn't exact. FrankenPHP does manage the event loop (the Go > > > runtime manages it - through a channel - under the hood). > > > > > > Perhaps "event loop" was the wrong term; what I was highlighting is that > > to use FrankenPHP or RoadRunner, you have to write a while loop, which > > explicitly handles one request at a time. In Swoole, there is no such > > loop: you register event handlers and then call $server->run() once. > > Similarly, WSGI mandates that the server "invokes the application > > callable once for each request it receives from an HTTP client". > > > > It's a distinction of pull/poll (the application must actively block > > until next request) vs push/subscribe (the application is passively > > invoked whenever needed). > > I think these models have different capabilities: A pull/poll model is > quite simple, while a subscription model is usually more complex. > > With something simple like in FrankenPHP, creating a Queue SAPI, a > WebSocket SAPI, etc isn't far off, where someone writes some PHP to > consume a queue or websocket connections. > > > > I already replied to Crell about that. It will totally possible to > > > expose more complex HTTP message objects in the future, > > > but PHP currently lacks such objects. The only things we have are > > > superglobals (which are more or less similar to CGI variables, as done > > > in WSGI) and streams. It's why we're using them. > > > > > > The use of objects vs arrays wasn't the main difference I was trying to > > highlight there, but rather the overall API of how information gets into > > and out of the application. FrankenPHP is the only server listed which > > needs to reset global state on each request, because the others > > (including Python WSGI and ASGI) use non-global variables for both input > > and output. > > > > I notice that the Laravel Octane adaptor for FrankenPHP takes that > > global state and immediately converts it into non-global variables for > > consumption by the application. > > For this to happen in PHP Core, there would need to be request objects > instead of a global state. If an RFC implementing PSR > requests/responses in Core is a pre-requisite for enabling what we're > discussing here, I'd personally be all for that (as would a very large > chunk of the PHP community, IMHO). I personally think this is a > chicken/egg type of problem though. It doesn't make sense to have > request/response objects right now, and I get the feeling that people > would only support worker mode primitives if there were request > objects... so, it might make sense to build a v1 of the worker mode > primitives and then iterate towards request objects, because then > there would be an actual need for them. > That is certainly not true. Looking at WSGI or ASGI there is no need for request response objects. These can be provided in userland which gives more flexibility cause of different rules governing over bc break policy in PHP core. Name one true argument to convince me in this topic and I may change my mind. For the years I had the same impression but on low level the primitives are more flexible and we all know that. Cheers, Michał Marcin Brzuchalski >
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
> > - FrankenPHP expects the user to manage the main event loop ... > > > > > > This isn't exact. FrankenPHP does manage the event loop (the Go > > runtime manages it - through a channel - under the hood). > > > Perhaps "event loop" was the wrong term; what I was highlighting is that > to use FrankenPHP or RoadRunner, you have to write a while loop, which > explicitly handles one request at a time. In Swoole, there is no such > loop: you register event handlers and then call $server->run() once. > Similarly, WSGI mandates that the server "invokes the application > callable once for each request it receives from an HTTP client". > > It's a distinction of pull/poll (the application must actively block > until next request) vs push/subscribe (the application is passively > invoked whenever needed). I think these models have different capabilities: A pull/poll model is quite simple, while a subscription model is usually more complex. With something simple like in FrankenPHP, creating a Queue SAPI, a WebSocket SAPI, etc isn't far off, where someone writes some PHP to consume a queue or websocket connections. > > I already replied to Crell about that. It will totally possible to > > expose more complex HTTP message objects in the future, > > but PHP currently lacks such objects. The only things we have are > > superglobals (which are more or less similar to CGI variables, as done > > in WSGI) and streams. It's why we're using them. > > > The use of objects vs arrays wasn't the main difference I was trying to > highlight there, but rather the overall API of how information gets into > and out of the application. FrankenPHP is the only server listed which > needs to reset global state on each request, because the others > (including Python WSGI and ASGI) use non-global variables for both input > and output. > > I notice that the Laravel Octane adaptor for FrankenPHP takes that > global state and immediately converts it into non-global variables for > consumption by the application. For this to happen in PHP Core, there would need to be request objects instead of a global state. If an RFC implementing PSR requests/responses in Core is a pre-requisite for enabling what we're discussing here, I'd personally be all for that (as would a very large chunk of the PHP community, IMHO). I personally think this is a chicken/egg type of problem though. It doesn't make sense to have request/response objects right now, and I get the feeling that people would only support worker mode primitives if there were request objects... so, it might make sense to build a v1 of the worker mode primitives and then iterate towards request objects, because then there would be an actual need for them. Robert Landers Software Engineer Utrecht NL -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
Hi Rowan, pt., 29 gru 2023 o 23:56 Rowan Tommins napisał(a): > On 29/12/2023 21:14, Kévin Dunglas wrote: > ... > The use of objects vs arrays wasn't the main difference I was trying to > highlight there, but rather the overall API of how information gets into > and out of the application. FrankenPHP is the only server listed which > needs to reset global state on each request, because the others > (including Python WSGI and ASGI) use non-global variables for both input > and output. > I wasn't aware of ASGI, in the past I read about WSGI and noticed a PHP connector allowing the PHP app to run inside the WSGI server. I read most of the spec https://asgi.readthedocs.io/en/latest/specs/index.html yesterday and it sounds like a really solid solution. Personally, I'd love to see something similar for PHP. It'd clearly be something different from the usual PHP app where global $_GET|POST variables carry the HTTP request input. Solution taken by Python in fact is about returning a callable fulfilling a specific signature no matter if this is a simple function, closure or Object implementing __invoke function - and this gives much flexibility. I believe that considering the fact that ASGI provides an API for HTTP interaction including WebSockets that could only benefit to PHP ecosystem. In the past, I was thinking about something similar to adopting WSGI but was not aware of ASGI. Cheers, Michał Marcin Brzuchalski
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On 29/12/2023 21:14, Kévin Dunglas wrote: On Fri, Dec 29, 2023 at 8:14 PM Rowan Tommins wrote: - FrankenPHP expects the user to manage the main event loop ... This isn't exact. FrankenPHP does manage the event loop (the Go runtime manages it - through a channel - under the hood). Perhaps "event loop" was the wrong term; what I was highlighting is that to use FrankenPHP or RoadRunner, you have to write a while loop, which explicitly handles one request at a time. In Swoole, there is no such loop: you register event handlers and then call $server->run() once. Similarly, WSGI mandates that the server "invokes the application callable once for each request it receives from an HTTP client". It's a distinction of pull/poll (the application must actively block until next request) vs push/subscribe (the application is passively invoked whenever needed). I already replied to Crell about that. It will totally possible to expose more complex HTTP message objects in the future, but PHP currently lacks such objects. The only things we have are superglobals (which are more or less similar to CGI variables, as done in WSGI) and streams. It's why we're using them. The use of objects vs arrays wasn't the main difference I was trying to highlight there, but rather the overall API of how information gets into and out of the application. FrankenPHP is the only server listed which needs to reset global state on each request, because the others (including Python WSGI and ASGI) use non-global variables for both input and output. I notice that the Laravel Octane adaptor for FrankenPHP takes that global state and immediately converts it into non-global variables for consumption by the application. I'm not sure what you mean by "async PHP environment". OpenSwoole, AMPHP, ReactPHP, etc - servers which expose concurrency directly to the user of PHP. In those environments, global state isn't just reused between consecutive requests, it's shared between multiple requests running concurrently, so a global "current request" and "current response" have no meaning. WebSockets and WebTransport are a different kind of beast, they are much lower level than HTTP and will require a different API anyway (and probably a lot of other adaptations in core) to be supported in PHP. WebSocket support in PHP is just as real as worker modes and asynchronous concurrency. Swoole has a WebSocket implementation included in core [https://openswoole.com/docs/modules/swoole-websocket-server] and Roadrunner has a plugin for it [https://roadrunner.dev/docs/plugins-centrifuge/current] In both cases (and in ASGI), the same basic API is used as with HTTP, but using a more general concept of "events" in place of "requests". Other PHP implementations include Ratchet [http://socketo.me/] and AMPHP Websocket Server [https://github.com/amphp/websocket-server]. Note that both async and WebSockets were mentioned as possible "forward compatibility". If we're talking about "next generation SAPIs", these are the kinds of features that people will be - and already are - developing; so it seems foolish not to at least consider them when designing new baseline APIs. Regards, -- Rowan Tommins [IMSoP]
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On Fri, Dec 29, 2023 at 8:14 PM Rowan Tommins wrote: > - FrankenPHP expects the user to manage the main event loop, repeatedly > passing the server a function to be called once; it doesn't pass > anything into or out of the userland handler, instead resetting global > state to mimic a non-worker environment > [https://frankenphp.dev/docs/worker/#custom-apps] > This isn't exact. FrankenPHP does manage the event loop (the Go runtime manages it - through a channel - under the hood). The frankenphp_handle_request() pauses the thread until the Go runtime gives back control to the C thread (when a request is dispatched to this worker). It's actually very similar to WSGI. As I explained in my previous messages, it's expected that other SAPIs handle the event loop too (using the primitives provided by the language they are written in). > - RoadRunner doesn't use a callback at all, instead providing methods to > await a request and provide a response; it directly uses PSR-7 and > PSR-17 objects [https://roadrunner.dev/docs/php-worker/current/en] > - OpenSwoole manages the main loop itself, and uses lifecycle events to > interface to userland code; the HTTP 'Request' event is passed custom > Request and Response objects > [https://openswoole.com/docs/modules/swoole-http-server-on-request] > I already replied to Crell about that. It will totally possible to expose more complex HTTP message objects in the future, but PHP currently lacks such objects. The only things we have are superglobals (which are more or less similar to CGI variables, as done in WSGI) and streams. It's why we're using them. If PHP adds a higher-level API at some point, we'll be able to upgrade this part as every other part of the PHP code base. But it's an unrelated topic: having such higher-level representations of HTTP messages would be beneficial both in "normal" and in "worker" mode. > it would be adapted for an async PHP environment, or with WebSockets, > for instance. > I'm not sure what you mean by "async PHP environment". WebSockets and WebTransport are a different kind of beast, they are much lower level than HTTP and will require a different API anyway (and probably a lot of other adaptations in core) to be supported in PHP. In Go, for instance, the WebSocket and WebTransport APIs aren't the same as the HTTP API. Best regards,
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On 23/12/2023 20:34, Kévin Dunglas wrote: In addition to sharing code, maintenance, performance optimization, etc., the existence of a common infrastructure would standardize the way worker scripts are created and provide a high-level PHP API for writing worker scripts that work with all SAPIs that rely on this new feature. While this seems like a noble aim, there doesn't seem to be much consensus on what such an API should look like; from what I can see: - FrankenPHP expects the user to manage the main event loop, repeatedly passing the server a function to be called once; it doesn't pass anything into or out of the userland handler, instead resetting global state to mimic a non-worker environment [https://frankenphp.dev/docs/worker/#custom-apps] - RoadRunner doesn't use a callback at all, instead providing methods to await a request and provide a response; it directly uses PSR-7 and PSR-17 objects [https://roadrunner.dev/docs/php-worker/current/en] - OpenSwoole manages the main loop itself, and uses lifecycle events to interface to userland code; the HTTP 'Request' event is passed custom Request and Response objects [https://openswoole.com/docs/modules/swoole-http-server-on-request] It also seems relevant to mention the situation in Python: - WSGI specifies a Python-level interface between a web server and a web application / framework. The server side is expected to provide the event loop (unlike in FrankenPHP), and passes the application an environment dictionary (based on CGI) and a start_response callback. [https://peps.python.org/pep-/] - The newer ASGI generalises this interface into an asynchronous event handling system, including support for WebSockets. [https://asgi.readthedocs.io/en/latest/introduction.html] Out of all of these, the FrankenPHP approach seems to be the most basic, providing good backwards compatibility with PHP's normal "shared nothing" approach, but not much forwards compatibility - I can't see how it would be adapted for an async PHP environment, or with WebSockets, for instance. I'm sceptical how many SAPIs would actually implement it, rather than providing more powerful APIs. Regards, -- Rowan Tommins [IMSoP]
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
Hi On 12/25/23 19:56, Jordan LeDoux wrote: So you want to introduce a SAPI that doesn't work with any of the existing HTTP solutions people use that only supports HTTP requests? Or am I misunderstanding something? This sounds a bit like you want to merge in a tool that is designed for your personal product directly into core. FrankenPHP may be incredible and awesome, but the world runs on Apache and Nginx for HTTP requests. My understanding of the proposal in very simplified language is: A new function shall be added to be implemented by SAPIs that are capable of implementing the function correctly. This function effectively: 1. Flushes the pending headers (header() calls) and body (if any). 2. Blocks until a request arrives. 3. Sets the superglobals ($_GET, $_POST, ...) to the request's values. 4. Sets the php://input stream to that request's body. 5. Sets up default headers (e.g. x-powered-by, if enabled). Best regard Tim Düsterhus -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
> > So you want to introduce a SAPI that doesn't work with any of the existing > HTTP solutions people use that only supports HTTP requests? Or am I > misunderstanding something? > > This sounds a bit like you want to merge in a tool that is designed for > your personal product directly into core. FrankenPHP may be incredible and > awesome, but the world runs on Apache and Nginx for HTTP requests. > > To be honest, after trying RoadRunner (an alternative to FrankenPHP), I'm using it for all my projects if the framework and packages have no issues with this execution model. Only old codebases with extensive usage of global variables and stateful services are at risk. If you stick with readonly classes and follow best DI practices, there will be minimum to no issues. Symfomy is actively propagating safe coding styles. So from my POV it is not a problem that a new execution model will be supported. If your code is not compatible - then this is your problem. It is normal that some code may not work properly in different modes. The fact that the world is running on Apache and Nginx doesn't mean this will be forever with no alternatives. The fact that there are multiple projects with the same goal shows that there is a big demand for PHP speedup. And there are no visible alternatives except a worker mode. IMO.
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
Hello, On Tue, Dec 26, 2023, 1:56 AM Jordan LeDoux wrote: > > So you want to introduce a SAPI that doesn't work with any of the existing > HTTP solutions people use that only supports HTTP requests? Or am I > misunderstanding something? > > This sounds a bit like you want to merge in a tool that is designed for > your personal product directly into core. FrankenPHP may be incredible and > awesome, but the world runs on Apache and Nginx for HTTP requests. The world was running on cgi when php was created and a few years after. Then the world was running on threads/apache. Then it ran in fcgi and finally fcgi fpm for the last few years. Other languages support this since quite some time. Projects like reactphp, swoole and the likes provide userland versions of it and the benefits are clear. They even worked together recently to get a common core. Many (large) projects out there already support FrankenPHP, the needs are there. FrankenPhp and a worker mode go beyond the classical php usages we had. Desktop applications or IoT are getting more common (see laravel's nativephp f.e.). I have done something similar for one of our products using embedded sapi but how it is done using frankenphp would be an order of magnitude better. Having the complex parts in the core us a good start to experiment, adapt. Later a core sapi may be added, we cannot know without trying and let the community uses it. best, Pierre
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
Why not just build this into the embed sapi instead? since its only for third party sapis? On 2023-12-23 1:34 p.m., Kévin Dunglas wrote: Hello and Merry Christmas! One of the main features of FrankenPHP is its worker mode, which lets you keep a PHP application in memory to handle multiple HTTP requests. Worker modes are becoming increasingly popular in the PHP world. Symfony (Runtime Component), Laravel (Octane), and many projects based on these frameworks (API Platform, Sulu...) now support a worker mode. In addition to FrankenPHP, projects such as RoadRunner and Swoole provide engines supporting worker modes. According to benchmarks, worker modes can improve the performance of PHP applications by up to 15 times. In addition to FrankenPHP, which is basically a SAPI for Go's integrated web server, a new generation of SAPIs is currently under development. Several SAPIs written in Rust (including one by the RoadRunner team) are currently under development. These SAPIs, along with existing SAPIs, could benefit from a shared infrastructure to build worker modes. The FrankenPHP code is written and should be easy to move around in PHP itself, to enable other SAPIs to use it. In addition to sharing code, maintenance, performance optimization, etc., the existence of a common infrastructure would standardize the way worker scripts are created and provide a high-level PHP API for writing worker scripts that work with all SAPIs that rely on this new feature. SAPIs will still have to handle fetching requests from the web server and pausing the worker to wait for new requests (in FrankenPHP, we use GoRoutines for this, in Rust or C, other primitives will have to be used), but almost everything else could be shared. For reference, here's the FrankenPHP code I propose to integrate into libphp: https://github.com/dunglas/frankenphp/blob/main/frankenphp.c#L245 The public API is documented here: https://frankenphp.dev/docs/worker/#custom-apps I'd like to hear what the community thinks about this. Would you be interested in this functionality in PHP? Should I work on an RFC? If there's interest, I can work on a patch. Cheers, -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
Hi, On Tue, Dec 26, 2023 at 12:09 AM Robert Landers wrote: > Hi Jakub, > > > I have been thinking about something similar for FPM and if you had some > > sort pool manager process, you could maybe do some sort of initial > > execution but then it gets really tricky especially with sharing > resources > > and managing connections. I think it would be a big can of worms so I > don't > > think this is going to happen anytime soon. > > It's already happening. Most libraries (particularly popular ones in > the Symfony/Laravel world) already support most of this > out-of-the-box. I love stateless servers, but sometimes a stateful > server is better. What is really nice about worker mode is that you > can actually have a PHP-native in-memory database that only exists for > as long as the worker is running (I do this for some unit tests). > > This was just about FPM. What I meant that this is not going to be supported by FPM anytime soon if ever. > > I could imaging that there will > > be similar issues for Apache prefork which is likely the most used MPM > for > > legacy apps. Effectively it means that this function won't be working on > > most installations as two of the likely most used SAPI's won't support > it. > > I think it should be pretty clear from the beginning. > > Most people are familiar with fastcgi_finish_request() and there are > some built-in SAPI's that don't support it. I don't think that just > because it won't start out with full support, it should be discarded. > > I didn't mean that it shouldn't be added. It should just be clear from the beginning that this will be for limited set of SAPIs. > > It would be also good to put together some base design PR for this as > > currently SAPI common functions are implemented separately in each SAPI > > (e.g. apache_request_headers). From the linked functionality, it is is > not > > a big amount of code and seems somehow specific to the FrankenPHP so why > > couldn't each SAPI just implement this function separately? I know that > > this is not ideal but it's what is already used for > apache_request_headers. > > I think otherwise you would need some hooking mechanism that should have > > some default (which would probably just throw exception) because it is > not > > going to be implemented by all SAPI's. I think it would be really good if > > you could provide more details about planned implementation for this. > > Most (all?) modern SAPI (lightspeed, roadrunner, etc) implements > fastcgi_finish_request(), even if no fastcgi is involved, simply > because of backward compatibility. It'd be great to actually bikeshed > a decent name and syntax/semantics before something popular comes > along and forces us all to use frankenphp_handle_request() or > something, simply because of backward compatibility. > I agree that coming up with some sensible name and API would be a good think even though it will have limited use in core. And if it gives us some coverage of embed SAPI (libphp), then it's even better. Cheers Jakub
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On Mon, Dec 25, 2023 at 7:06 PM Kévin Dunglas wrote: > > On Mon, Dec 25, 2023 at 6:30 PM Jakub Zelenka wrote: > >> >> >> On Mon, Dec 25, 2023 at 12:34 PM Kévin Dunglas wrote: >> >>> On Sun, Dec 24, 2023 at 4:21 PM Larry Garfield >>> wrote: >>> >>> In practice, I want to understand the implications for user-space code. >>> > Does this mean FPM could be configured in a way to execute a file like >>> that >>> > shown in the docs page above? Or would it only work with third party >>> SAPIs >>> > like FrankenPHP? >>> >>> >>> In theory, PHP-FPM and the Apache module could - like all other SAPIs - >>> be >>> enhanced to add a worker mode operating as described in the FrankenPHP >>> doc >>> thanks to these new primitives. >>> >> >> I have been thinking about something similar for FPM and if you had some >> sort pool manager process, you could maybe do some sort of initial >> execution but then it gets really tricky especially with sharing resources >> and managing connections. I think it would be a big can of worms so I don't >> think this is going to happen anytime soon. I could imaging that there will >> be similar issues for Apache prefork which is likely the most used MPM for >> legacy apps. Effectively it means that this function won't be working on >> most installations as two of the likely most used SAPI's won't support it. >> I think it should be pretty clear from the beginning. >> >> >>> However, I suggest doing this as a second step, because as described in >>> my >>> first post, it will still be the responsibility of each SAPI to manage >>> long-running processes and communication with them. This is simple to do >>> with Go's GoRoutine and Rust's asynchronous runtimes such as Tokio, it's >>> definitely more difficult in cross-platform C. I suggest starting by >>> adding >>> the primitives to libphp, then we'll see how to exploit them (and whether >>> it's worthwhile) in the built-in SAPIs. >>> >> >> The problem with this is that we would add some code that won't be used >> by any of the built in SAPI which means that that we won't be able to have >> automated tests for this. So the minimum should be to have at least one >> core SAPI supporting this new functionality. I wouldn't mind if it's just a >> SAPI for testing purpose which might be actually useful for testing embed >> SAPI code. I think that should be a requirement for accepting a PR >> introducing this. >> >> It would be also good to put together some base design PR for this as >> currently SAPI common functions are implemented separately in each SAPI >> (e.g. apache_request_headers). From the linked functionality, it is is not >> a big amount of code and seems somehow specific to the FrankenPHP so why >> couldn't each SAPI just implement this function separately? I know that >> this is not ideal but it's what is already used for apache_request_headers. >> I think otherwise you would need some hooking mechanism that should have >> some default (which would probably just throw exception) because it is not >> going to be implemented by all SAPI's. I think it would be really good if >> you could provide more details about planned implementation for this. >> >> >>> I personally have less interest in working on FPM/CGI/mod_php as the >>> other >>> possibilities offered by modern SAPIs like FrankenPHP are more important >>> (better deployment experience as you have a single static binary or >>> Docker >>> image, Early Hints support, high-quality native HTTP/3 server etc) >>> >>> >> Except that those are all threaded SAPIs so they offer less separation >> and protection against application crashes in addition to the fact that >> thread management in PHP still has got its own issues. They are certainly >> some advantages especially for thin services but if you have huge monolith >> codebase like some big CMS and other projects, then I would probably stick >> with process separation model. >> >> Cheers >> >> Jakub >> > > Sure, the main targets are new SAPIs like FrankenPHP and the one in Rust > developed by the RoadRunner team. I thought it was clear in my previous > messages but I'll be glad to make it bold in the RFC. > The way how I read was that this would be eventually supported by all SAPIs which I think is not likely going to be the case. > Automated tests (likely through a test SAPI) will definitely be needed. > Throwing if the current SAPI doesn't support (yet) the new userland > function looks sensitive. > > +1 > Couldn't this shared code be put in "main", as it could (theoretically, I > agree that it will be hard to do for existing core SAPIs) be used by all > SAPIs? > The main does not have a module but it could be probably added to standard ext like it's the case for other functionality related to main. Cheers Jakub
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
Hi Jakub, > I have been thinking about something similar for FPM and if you had some > sort pool manager process, you could maybe do some sort of initial > execution but then it gets really tricky especially with sharing resources > and managing connections. I think it would be a big can of worms so I don't > think this is going to happen anytime soon. It's already happening. Most libraries (particularly popular ones in the Symfony/Laravel world) already support most of this out-of-the-box. I love stateless servers, but sometimes a stateful server is better. What is really nice about worker mode is that you can actually have a PHP-native in-memory database that only exists for as long as the worker is running (I do this for some unit tests). > I could imaging that there will > be similar issues for Apache prefork which is likely the most used MPM for > legacy apps. Effectively it means that this function won't be working on > most installations as two of the likely most used SAPI's won't support it. > I think it should be pretty clear from the beginning. Most people are familiar with fastcgi_finish_request() and there are some built-in SAPI's that don't support it. I don't think that just because it won't start out with full support, it should be discarded. > It would be also good to put together some base design PR for this as > currently SAPI common functions are implemented separately in each SAPI > (e.g. apache_request_headers). From the linked functionality, it is is not > a big amount of code and seems somehow specific to the FrankenPHP so why > couldn't each SAPI just implement this function separately? I know that > this is not ideal but it's what is already used for apache_request_headers. > I think otherwise you would need some hooking mechanism that should have > some default (which would probably just throw exception) because it is not > going to be implemented by all SAPI's. I think it would be really good if > you could provide more details about planned implementation for this. Most (all?) modern SAPI (lightspeed, roadrunner, etc) implements fastcgi_finish_request(), even if no fastcgi is involved, simply because of backward compatibility. It'd be great to actually bikeshed a decent name and syntax/semantics before something popular comes along and forces us all to use frankenphp_handle_request() or something, simply because of backward compatibility. I think this functionality unlocks some really cool potential powers (in-memory databases for development, connection pooling without an extension, etc) and it's worth at least seriously considering implementing it in core. - Rob -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On Mon, Dec 25, 2023 at 7:56 PM Jordan LeDoux wrote: > > > On Mon, Dec 25, 2023 at 8:19 AM Kévin Dunglas wrote: > >> >> On Sun, Dec 24, 2023 at 10:44 PM Jordan LeDoux >> wrote: >> >>> >>> >>> On Sat, Dec 23, 2023 at 12:34 PM Kévin Dunglas wrote: >>> Hello and Merry Christmas! One of the main features of FrankenPHP is its worker mode, which lets you keep a PHP application in memory to handle multiple HTTP requests. Worker modes are becoming increasingly popular in the PHP world. Symfony (Runtime Component), Laravel (Octane), and many projects based on these frameworks (API Platform, Sulu...) now support a worker mode. In addition to FrankenPHP, projects such as RoadRunner and Swoole provide engines supporting worker modes. According to benchmarks, worker modes can improve the performance of PHP applications by up to 15 times. In addition to FrankenPHP, which is basically a SAPI for Go's integrated web server, a new generation of SAPIs is currently under development. Several SAPIs written in Rust (including one by the RoadRunner team) are currently under development. These SAPIs, along with existing SAPIs, could benefit from a shared infrastructure to build worker modes. The FrankenPHP code is written and should be easy to move around in PHP itself, to enable other SAPIs to use it. In addition to sharing code, maintenance, performance optimization, etc., the existence of a common infrastructure would standardize the way worker scripts are created and provide a high-level PHP API for writing worker scripts that work with all SAPIs that rely on this new feature. SAPIs will still have to handle fetching requests from the web server and pausing the worker to wait for new requests (in FrankenPHP, we use GoRoutines for this, in Rust or C, other primitives will have to be used), but almost everything else could be shared. For reference, here's the FrankenPHP code I propose to integrate into libphp: https://github.com/dunglas/frankenphp/blob/main/frankenphp.c#L245 The public API is documented here: https://frankenphp.dev/docs/worker/#custom-apps I'd like to hear what the community thinks about this. Would you be interested in this functionality in PHP? Should I work on an RFC? If there's interest, I can work on a patch. Cheers, -- Kévin Dunglas >>> >>> Much like Larry, I'm curious what sort of scope you imagine for this. >>> Are you imagining something that is geared specifically towards HTTP >>> requests, or would this be a more generic "PHP Application Worker" that >>> might be spawned to handle other types of applications? Could we have a >>> worker listen to a specific port and respond to or handle all requests on >>> that port/device? >>> >>> Jordan >>> >> >> Ho Jordan, >> >> Yes, the scope I imagine is geared specifically towards HTTP requests. >> Something more generic than common primitives for SAPIs and a shared public >> API to handle HTTP requests with a long-running PHP worker script will be >> hard to do outside of SAPIs because they depend on a lot of external >> concerns such as the programming language the SAPI is using. >> > > So you want to introduce a SAPI that doesn't work with any of the existing > HTTP solutions people use that only supports HTTP requests? Or am I > misunderstanding something? > > This sounds a bit like you want to merge in a tool that is designed for > your personal product directly into core. FrankenPHP may be incredible and > awesome, but the world runs on Apache and Nginx for HTTP requests. > > Jordan > As explained in the initial message and in my reply to Jakub, the main targets are emerging SAPIs. We have no interest (quite the contrary) in moving this code from FrankenPHP to PHP core (harder maintenance, slower iterations as more collaboration will be involved...), but I do think that having a "standard" and shared infrastructure and API for worker modes between new generation SAPIs will be beneficial to the community as a whole (no need - as at present - to write a different worker script for each engine having a worker mode, sharing of optimizations, security patches etc...). We're talking roughly about a C function of a few dozen lines, not something very big.
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On Mon, Dec 25, 2023 at 6:30 PM Jakub Zelenka wrote: > > > On Mon, Dec 25, 2023 at 12:34 PM Kévin Dunglas wrote: > >> On Sun, Dec 24, 2023 at 4:21 PM Larry Garfield >> wrote: >> >> In practice, I want to understand the implications for user-space code. >> > Does this mean FPM could be configured in a way to execute a file like >> that >> > shown in the docs page above? Or would it only work with third party >> SAPIs >> > like FrankenPHP? >> >> >> In theory, PHP-FPM and the Apache module could - like all other SAPIs - be >> enhanced to add a worker mode operating as described in the FrankenPHP doc >> thanks to these new primitives. >> > > I have been thinking about something similar for FPM and if you had some > sort pool manager process, you could maybe do some sort of initial > execution but then it gets really tricky especially with sharing resources > and managing connections. I think it would be a big can of worms so I don't > think this is going to happen anytime soon. I could imaging that there will > be similar issues for Apache prefork which is likely the most used MPM for > legacy apps. Effectively it means that this function won't be working on > most installations as two of the likely most used SAPI's won't support it. > I think it should be pretty clear from the beginning. > > >> However, I suggest doing this as a second step, because as described in my >> first post, it will still be the responsibility of each SAPI to manage >> long-running processes and communication with them. This is simple to do >> with Go's GoRoutine and Rust's asynchronous runtimes such as Tokio, it's >> definitely more difficult in cross-platform C. I suggest starting by >> adding >> the primitives to libphp, then we'll see how to exploit them (and whether >> it's worthwhile) in the built-in SAPIs. >> > > The problem with this is that we would add some code that won't be used by > any of the built in SAPI which means that that we won't be able to have > automated tests for this. So the minimum should be to have at least one > core SAPI supporting this new functionality. I wouldn't mind if it's just a > SAPI for testing purpose which might be actually useful for testing embed > SAPI code. I think that should be a requirement for accepting a PR > introducing this. > > It would be also good to put together some base design PR for this as > currently SAPI common functions are implemented separately in each SAPI > (e.g. apache_request_headers). From the linked functionality, it is is not > a big amount of code and seems somehow specific to the FrankenPHP so why > couldn't each SAPI just implement this function separately? I know that > this is not ideal but it's what is already used for apache_request_headers. > I think otherwise you would need some hooking mechanism that should have > some default (which would probably just throw exception) because it is not > going to be implemented by all SAPI's. I think it would be really good if > you could provide more details about planned implementation for this. > > >> I personally have less interest in working on FPM/CGI/mod_php as the other >> possibilities offered by modern SAPIs like FrankenPHP are more important >> (better deployment experience as you have a single static binary or Docker >> image, Early Hints support, high-quality native HTTP/3 server etc) >> >> > Except that those are all threaded SAPIs so they offer less separation and > protection against application crashes in addition to the fact that thread > management in PHP still has got its own issues. They are certainly some > advantages especially for thin services but if you have huge monolith > codebase like some big CMS and other projects, then I would probably stick > with process separation model. > > Cheers > > Jakub > Sure, the main targets are new SAPIs like FrankenPHP and the one in Rust developed by the RoadRunner team. I thought it was clear in my previous messages but I'll be glad to make it bold in the RFC. Automated tests (likely through a test SAPI) will definitely be needed. Throwing if the current SAPI doesn't support (yet) the new userland function looks sensitive. Couldn't this shared code be put in "main", as it could (theoretically, I agree that it will be hard to do for existing core SAPIs) be used by all SAPIs?
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On Mon, Dec 25, 2023 at 8:19 AM Kévin Dunglas wrote: > > On Sun, Dec 24, 2023 at 10:44 PM Jordan LeDoux > wrote: > >> >> >> On Sat, Dec 23, 2023 at 12:34 PM Kévin Dunglas wrote: >> >>> Hello and Merry Christmas! >>> >>> One of the main features of FrankenPHP is its worker mode, which lets you >>> keep a PHP application in memory to handle multiple HTTP requests. >>> >>> Worker modes are becoming increasingly popular in the PHP world. Symfony >>> (Runtime Component), Laravel (Octane), and many projects based on these >>> frameworks (API Platform, Sulu...) now support a worker mode. >>> >>> In addition to FrankenPHP, projects such as RoadRunner and Swoole provide >>> engines supporting worker modes. >>> >>> According to benchmarks, worker modes can improve the performance of PHP >>> applications by up to 15 times. >>> In addition to FrankenPHP, which is basically a SAPI for Go's integrated >>> web server, a new generation of SAPIs is currently under development. >>> Several SAPIs written in Rust (including one by the RoadRunner team) are >>> currently under development. >>> >>> These SAPIs, along with existing SAPIs, could benefit from a shared >>> infrastructure to build worker modes. >>> >>> >>> >>> The FrankenPHP code is written and should be easy to move around in PHP >>> itself, to enable other SAPIs to use it. >>> >>> In addition to sharing code, maintenance, performance optimization, etc., >>> the existence of a common infrastructure would standardize the way worker >>> scripts are created and provide a high-level PHP API for writing worker >>> scripts that work with all SAPIs that rely on this new feature. >>> >>> SAPIs will still have to handle fetching requests from the web server and >>> pausing the worker to wait for new requests (in FrankenPHP, we use >>> GoRoutines for this, in Rust or C, other primitives will have to be >>> used), >>> but almost everything else could be shared. >>> >>> For reference, here's the FrankenPHP code I propose to integrate into >>> libphp: >>> https://github.com/dunglas/frankenphp/blob/main/frankenphp.c#L245 >>> >>> The public API is documented here: >>> https://frankenphp.dev/docs/worker/#custom-apps >>> >>> I'd like to hear what the community thinks about this. Would you be >>> interested in this functionality in PHP? Should I work on an RFC? >>> >>> If there's interest, I can work on a patch. >>> >>> Cheers, >>> -- >>> Kévin Dunglas >>> >> >> Much like Larry, I'm curious what sort of scope you imagine for this. Are >> you imagining something that is geared specifically towards HTTP requests, >> or would this be a more generic "PHP Application Worker" that might be >> spawned to handle other types of applications? Could we have a worker >> listen to a specific port and respond to or handle all requests on that >> port/device? >> >> Jordan >> > > Ho Jordan, > > Yes, the scope I imagine is geared specifically towards HTTP requests. > Something more generic than common primitives for SAPIs and a shared public > API to handle HTTP requests with a long-running PHP worker script will be > hard to do outside of SAPIs because they depend on a lot of external > concerns such as the programming language the SAPI is using. > So you want to introduce a SAPI that doesn't work with any of the existing HTTP solutions people use that only supports HTTP requests? Or am I misunderstanding something? This sounds a bit like you want to merge in a tool that is designed for your personal product directly into core. FrankenPHP may be incredible and awesome, but the world runs on Apache and Nginx for HTTP requests. Jordan
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On Mon, Dec 25, 2023 at 12:34 PM Kévin Dunglas wrote: > On Sun, Dec 24, 2023 at 4:21 PM Larry Garfield > wrote: > > In practice, I want to understand the implications for user-space code. > > Does this mean FPM could be configured in a way to execute a file like > that > > shown in the docs page above? Or would it only work with third party > SAPIs > > like FrankenPHP? > > > In theory, PHP-FPM and the Apache module could - like all other SAPIs - be > enhanced to add a worker mode operating as described in the FrankenPHP doc > thanks to these new primitives. > I have been thinking about something similar for FPM and if you had some sort pool manager process, you could maybe do some sort of initial execution but then it gets really tricky especially with sharing resources and managing connections. I think it would be a big can of worms so I don't think this is going to happen anytime soon. I could imaging that there will be similar issues for Apache prefork which is likely the most used MPM for legacy apps. Effectively it means that this function won't be working on most installations as two of the likely most used SAPI's won't support it. I think it should be pretty clear from the beginning. > However, I suggest doing this as a second step, because as described in my > first post, it will still be the responsibility of each SAPI to manage > long-running processes and communication with them. This is simple to do > with Go's GoRoutine and Rust's asynchronous runtimes such as Tokio, it's > definitely more difficult in cross-platform C. I suggest starting by adding > the primitives to libphp, then we'll see how to exploit them (and whether > it's worthwhile) in the built-in SAPIs. > The problem with this is that we would add some code that won't be used by any of the built in SAPI which means that that we won't be able to have automated tests for this. So the minimum should be to have at least one core SAPI supporting this new functionality. I wouldn't mind if it's just a SAPI for testing purpose which might be actually useful for testing embed SAPI code. I think that should be a requirement for accepting a PR introducing this. It would be also good to put together some base design PR for this as currently SAPI common functions are implemented separately in each SAPI (e.g. apache_request_headers). From the linked functionality, it is is not a big amount of code and seems somehow specific to the FrankenPHP so why couldn't each SAPI just implement this function separately? I know that this is not ideal but it's what is already used for apache_request_headers. I think otherwise you would need some hooking mechanism that should have some default (which would probably just throw exception) because it is not going to be implemented by all SAPI's. I think it would be really good if you could provide more details about planned implementation for this. > I personally have less interest in working on FPM/CGI/mod_php as the other > possibilities offered by modern SAPIs like FrankenPHP are more important > (better deployment experience as you have a single static binary or Docker > image, Early Hints support, high-quality native HTTP/3 server etc) > > Except that those are all threaded SAPIs so they offer less separation and protection against application crashes in addition to the fact that thread management in PHP still has got its own issues. They are certainly some advantages especially for thin services but if you have huge monolith codebase like some big CMS and other projects, then I would probably stick with process separation model. Cheers Jakub
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
> Forgive my ignorance, but why no connection? You mean the > pre-worker-start part needs to avoid an SQL connection? Why is that? That > would be something that needs to be super-well documented, and possibly > some guards in place to prevent it, if there's no good way around it. > (This is the sort of detail I'm thinking of, where I just don't know the > implications but want to think through them as much as possible in advance, > so that it can be "safe by design.") > Sorry, I made a typo. I mean "libraries must ensure that the connection **is** active" (if the connection timeout has been reached, the library must reconnect). Your worker script will be long-running code, as in Java, Go, etc. So if it depends on external services, it must check that the connection is still active, and reconnect if necessary. This is the default in most languages, but not in PHP (yet). Do you have an intent or expectation of a worker-style SAPI being shipped > with PHP itself, or for that to remain the domain of third parties? > As I tried to explain in my previous message, this could be nice, and possible, but I don't plan to do it myself for now :) > I mean more what implications would there be on how user-space code is > written to be worker-SAPI-friendly. (The SQL connection comment above, for > example.) I have not worked with any of the worker-ish tools so far > myself, so other than "you'll need an alternate index.php for that", I > don't have a good sense of what else I'd want to do differently to play > nice with Franken and Friends. > As far as I know, there are no other implications than memory (and other resources) leaks (https://laravel.com/docs/10.x/octane#managing-memory-leaks) and timeout handling. > The idea of combining fiber-based code with supported worker-mode runners > sounds like a ridiculously cool future for PHP, but I don't know how windy > that path is. :-) > That already works if you use FrankenPHP! Joe also experimented successfully using the parallel extension instead of Fibers: https://twitter.com/krakjoe/status/1587234661696245760
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On Mon, Dec 25, 2023, at 6:34 AM, Kévin Dunglas wrote: > However, I suggest doing this as a second step, because as described in > my first post, it will still be the responsibility of each SAPI to > manage long-running processes and communication with them. This is > simple to do with Go's GoRoutine and Rust's asynchronous runtimes such > as Tokio, it's definitely more difficult in cross-platform C. I suggest > starting by adding the primitives to libphp, then we'll see how to > exploit them (and whether it's worthwhile) in the built-in SAPIs. > I personally have less interest in working on FPM/CGI/mod_php as the > other possibilities offered by modern SAPIs like FrankenPHP are more > important (better deployment experience as you have a single static > binary or Docker image, Early Hints support, high-quality native HTTP/3 > server etc), but I'd be happy to help if anyone wants to update these > SAPIs. >> To what extent would user-space code run this way have to think about >> concurrency, shared memory, persistent SQL connections, etc? Does it have >> any implications for fiber-using async code? > > Regarding concurrency, it doesn't change much (it's similar to existing > SAPI). Regarding memory and SQL connections, extra care is required. > Memory leaks (and other kinds of leaks) should be avoided (or workers > should restart from time to time, which is obviously a poorer > solution). Libraries maintaining SQL connections such as Doctrine or > Eloquent must ensure that the connection isn't active. Forgive my ignorance, but why no connection? You mean the pre-worker-start part needs to avoid an SQL connection? Why is that? That would be something that needs to be super-well documented, and possibly some guards in place to prevent it, if there's no good way around it. (This is the sort of detail I'm thinking of, where I just don't know the implications but want to think through them as much as possible in advance, so that it can be "safe by design.") > Fibers work as expected. There is a small limitation when using them > with Go (that is being tracked in the Go runtime, > https://frankenphp.dev/docs/known-issues/#fibers), but it's not related > to the C code of the worker mode, and this limitation shouldn't exist > for SAPIs not written in Go. > >> Depending on the details, this could be like fibers but for 3rd party SAPIs >> (something about 4 people in the world actually care about directly, >> everyone else just uses Revolt, Amp, or React, but mostly it doesn't get >> used), or completely changing the way 90% of the market runs PHP, which >> means frameworks will likely adapt to use that model primarily or >> exclusively (ie, less of a need for a "compile" step as a generated >> container or dispatcher is just held in memory automatically already). The >> latter sounds exciting to me, but I'm not sure which is your intent, so I >> don't know if I'm going too far with it. :-) > > My intent is that most SAPIs expose the same (or a very similar > interoperable) worker mode. So (I hope) that most PHP developers will > not have to deal with these primitives directly, but that it will allow > a new generation of super-fast PHP apps to be created. Most frameworks > already support that but require a lot of boilerplate code to support > the different existing engines. Standardizing will likely increase > adoption and will allow collaboration to make the low-level code that I > propose to move in libphp as fast, stable, and clean as possible. Do you have an intent or expectation of a worker-style SAPI being shipped with PHP itself, or for that to remain the domain of third parties? >> Please advise on what the implications would be for the non-SAPI-developing >> PHP devs out there. > > None, except that they will be able to use the new handle_request() > function to create a worker script if supported by the SAPI they use. I mean more what implications would there be on how user-space code is written to be worker-SAPI-friendly. (The SQL connection comment above, for example.) I have not worked with any of the worker-ish tools so far myself, so other than "you'll need an alternate index.php for that", I don't have a good sense of what else I'd want to do differently to play nice with Franken and Friends. The idea of combining fiber-based code with supported worker-mode runners sounds like a ridiculously cool future for PHP, but I don't know how windy that path is. :-) --Larry Garfield -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On Sun, Dec 24, 2023 at 10:44 PM Jordan LeDoux wrote: > > > On Sat, Dec 23, 2023 at 12:34 PM Kévin Dunglas wrote: > >> Hello and Merry Christmas! >> >> One of the main features of FrankenPHP is its worker mode, which lets you >> keep a PHP application in memory to handle multiple HTTP requests. >> >> Worker modes are becoming increasingly popular in the PHP world. Symfony >> (Runtime Component), Laravel (Octane), and many projects based on these >> frameworks (API Platform, Sulu...) now support a worker mode. >> >> In addition to FrankenPHP, projects such as RoadRunner and Swoole provide >> engines supporting worker modes. >> >> According to benchmarks, worker modes can improve the performance of PHP >> applications by up to 15 times. >> In addition to FrankenPHP, which is basically a SAPI for Go's integrated >> web server, a new generation of SAPIs is currently under development. >> Several SAPIs written in Rust (including one by the RoadRunner team) are >> currently under development. >> >> These SAPIs, along with existing SAPIs, could benefit from a shared >> infrastructure to build worker modes. >> >> >> >> The FrankenPHP code is written and should be easy to move around in PHP >> itself, to enable other SAPIs to use it. >> >> In addition to sharing code, maintenance, performance optimization, etc., >> the existence of a common infrastructure would standardize the way worker >> scripts are created and provide a high-level PHP API for writing worker >> scripts that work with all SAPIs that rely on this new feature. >> >> SAPIs will still have to handle fetching requests from the web server and >> pausing the worker to wait for new requests (in FrankenPHP, we use >> GoRoutines for this, in Rust or C, other primitives will have to be used), >> but almost everything else could be shared. >> >> For reference, here's the FrankenPHP code I propose to integrate into >> libphp: https://github.com/dunglas/frankenphp/blob/main/frankenphp.c#L245 >> >> The public API is documented here: >> https://frankenphp.dev/docs/worker/#custom-apps >> >> I'd like to hear what the community thinks about this. Would you be >> interested in this functionality in PHP? Should I work on an RFC? >> >> If there's interest, I can work on a patch. >> >> Cheers, >> -- >> Kévin Dunglas >> > > Much like Larry, I'm curious what sort of scope you imagine for this. Are > you imagining something that is geared specifically towards HTTP requests, > or would this be a more generic "PHP Application Worker" that might be > spawned to handle other types of applications? Could we have a worker > listen to a specific port and respond to or handle all requests on that > port/device? > > Jordan > Ho Jordan, Yes, the scope I imagine is geared specifically towards HTTP requests. Something more generic than common primitives for SAPIs and a shared public API to handle HTTP requests with a long-running PHP worker script will be hard to do outside of SAPIs because they depend on a lot of external concerns such as the programming language the SAPI is using.
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On Sun, Dec 24, 2023 at 4:21 PM Larry Garfield wrote: In practice, I want to understand the implications for user-space code. > Does this mean FPM could be configured in a way to execute a file like that > shown in the docs page above? Or would it only work with third party SAPIs > like FrankenPHP? In theory, PHP-FPM and the Apache module could - like all other SAPIs - be enhanced to add a worker mode operating as described in the FrankenPHP doc thanks to these new primitives. However, I suggest doing this as a second step, because as described in my first post, it will still be the responsibility of each SAPI to manage long-running processes and communication with them. This is simple to do with Go's GoRoutine and Rust's asynchronous runtimes such as Tokio, it's definitely more difficult in cross-platform C. I suggest starting by adding the primitives to libphp, then we'll see how to exploit them (and whether it's worthwhile) in the built-in SAPIs. I personally have less interest in working on FPM/CGI/mod_php as the other possibilities offered by modern SAPIs like FrankenPHP are more important (better deployment experience as you have a single static binary or Docker image, Early Hints support, high-quality native HTTP/3 server etc), but I'd be happy to help if anyone wants to update these SAPIs. I assume the handler function would be differently named. I suggest naming the function handle_request() or something similar and using the same name for all SAPIs, so the same worker script will work everywhere. I'll update FrankenPHP to use the "standard" name. > Is passing in super-globals the right/best way to handle each request, or > would it be sensible to have some other abstraction there? (Whether a > formal request object a la PSR-7 or something else.) Passing super-globals is at the same time the most interoperable solution (it allows using almost all existing PHP libraries in worker mode without any change to them), and also allows to reuse of the existing C code. Transforming super-globals in HttpFoundation, PSR-7, or other objects is straightforward and can entirely be done userland (it's already what the Symfony Runtime Component and Laravel Octane do), so there is no need to "bloat" the C code. Having more high-level data structures to manipulate HTTP messages similar to HttpFoundation or PSR-7 in the language could be nice (and is in my opinion needed), but is a separate topic. If PHP adds a new abstraction for that at some point, it will be easy to add support for them both in standard and worker mode. > To what extent would user-space code run this way have to think about > concurrency, shared memory, persistent SQL connections, etc? Does it have > any implications for fiber-using async code? > Regarding concurrency, it doesn't change much (it's similar to existing SAPI). Regarding memory and SQL connections, extra care is required. Memory leaks (and other kinds of leaks) should be avoided (or workers should restart from time to time, which is obviously a poorer solution). Libraries maintaining SQL connections such as Doctrine or Eloquent must ensure that the connection isn't active. The good news is that thanks to RoadRunner, Swoole, Laravel Octane, Symfony Runtime etc... Most popular libraries are already compatible with long-running processes, and most issues have been fixed. Some old apps and libraries will probably never be updatable, but that's not a big issue because this feature will be entirely opt-in. Fibers work as expected. There is a small limitation when using them with Go (that is being tracked in the Go runtime, https://frankenphp.dev/docs/known-issues/#fibers), but it's not related to the C code of the worker mode, and this limitation shouldn't exist for SAPIs not written in Go. > Depending on the details, this could be like fibers but for 3rd party > SAPIs (something about 4 people in the world actually care about directly, > everyone else just uses Revolt, Amp, or React, but mostly it doesn't get > used), or completely changing the way 90% of the market runs PHP, which > means frameworks will likely adapt to use that model primarily or > exclusively (ie, less of a need for a "compile" step as a generated > container or dispatcher is just held in memory automatically already). The > latter sounds exciting to me, but I'm not sure which is your intent, so I > don't know if I'm going too far with it. :-) > My intent is that most SAPIs expose the same (or a very similar interoperable) worker mode. So (I hope) that most PHP developers will not have to deal with these primitives directly, but that it will allow a new generation of super-fast PHP apps to be created. Most frameworks already support that but require a lot of boilerplate code to support the different existing engines. Standardizing will likely increase adoption and will allow collaboration to make the low-level code that I propose to move in libphp as fast, stable, and clean as possible. >
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On Sat, Dec 23, 2023 at 12:34 PM Kévin Dunglas wrote: > Hello and Merry Christmas! > > One of the main features of FrankenPHP is its worker mode, which lets you > keep a PHP application in memory to handle multiple HTTP requests. > > Worker modes are becoming increasingly popular in the PHP world. Symfony > (Runtime Component), Laravel (Octane), and many projects based on these > frameworks (API Platform, Sulu...) now support a worker mode. > > In addition to FrankenPHP, projects such as RoadRunner and Swoole provide > engines supporting worker modes. > > According to benchmarks, worker modes can improve the performance of PHP > applications by up to 15 times. > In addition to FrankenPHP, which is basically a SAPI for Go's integrated > web server, a new generation of SAPIs is currently under development. > Several SAPIs written in Rust (including one by the RoadRunner team) are > currently under development. > > These SAPIs, along with existing SAPIs, could benefit from a shared > infrastructure to build worker modes. > > > > The FrankenPHP code is written and should be easy to move around in PHP > itself, to enable other SAPIs to use it. > > In addition to sharing code, maintenance, performance optimization, etc., > the existence of a common infrastructure would standardize the way worker > scripts are created and provide a high-level PHP API for writing worker > scripts that work with all SAPIs that rely on this new feature. > > SAPIs will still have to handle fetching requests from the web server and > pausing the worker to wait for new requests (in FrankenPHP, we use > GoRoutines for this, in Rust or C, other primitives will have to be used), > but almost everything else could be shared. > > For reference, here's the FrankenPHP code I propose to integrate into > libphp: https://github.com/dunglas/frankenphp/blob/main/frankenphp.c#L245 > > The public API is documented here: > https://frankenphp.dev/docs/worker/#custom-apps > > I'd like to hear what the community thinks about this. Would you be > interested in this functionality in PHP? Should I work on an RFC? > > If there's interest, I can work on a patch. > > Cheers, > -- > Kévin Dunglas > Much like Larry, I'm curious what sort of scope you imagine for this. Are you imagining something that is geared specifically towards HTTP requests, or would this be a more generic "PHP Application Worker" that might be spawned to handle other types of applications? Could we have a worker listen to a specific port and respond to or handle all requests on that port/device? Jordan
Re: [PHP-DEV] RFC proposal: worker mode primitives for SAPIs
On Sat, Dec 23, 2023, at 2:34 PM, Kévin Dunglas wrote: > Hello and Merry Christmas! > > One of the main features of FrankenPHP is its worker mode, which lets you > keep a PHP application in memory to handle multiple HTTP requests. > > Worker modes are becoming increasingly popular in the PHP world. Symfony > (Runtime Component), Laravel (Octane), and many projects based on these > frameworks (API Platform, Sulu...) now support a worker mode. > > In addition to FrankenPHP, projects such as RoadRunner and Swoole provide > engines supporting worker modes. > > According to benchmarks, worker modes can improve the performance of PHP > applications by up to 15 times. > In addition to FrankenPHP, which is basically a SAPI for Go's integrated > web server, a new generation of SAPIs is currently under development. > Several SAPIs written in Rust (including one by the RoadRunner team) are > currently under development. > > These SAPIs, along with existing SAPIs, could benefit from a shared > infrastructure to build worker modes. > > > > The FrankenPHP code is written and should be easy to move around in PHP > itself, to enable other SAPIs to use it. > > In addition to sharing code, maintenance, performance optimization, etc., > the existence of a common infrastructure would standardize the way worker > scripts are created and provide a high-level PHP API for writing worker > scripts that work with all SAPIs that rely on this new feature. > > SAPIs will still have to handle fetching requests from the web server and > pausing the worker to wait for new requests (in FrankenPHP, we use > GoRoutines for this, in Rust or C, other primitives will have to be used), > but almost everything else could be shared. > > For reference, here's the FrankenPHP code I propose to integrate into > libphp: https://github.com/dunglas/frankenphp/blob/main/frankenphp.c#L245 > > The public API is documented here: > https://frankenphp.dev/docs/worker/#custom-apps > > I'd like to hear what the community thinks about this. Would you be > interested in this functionality in PHP? Should I work on an RFC? > > If there's interest, I can work on a patch. > > Cheers, In concept, I love this and would be ecstatic to see it happen. In practice, I want to understand the implications for user-space code. Does this mean FPM could be configured in a way to execute a file like that shown in the docs page above? Or would it only work with third party SAPIs like FrankenPHP? I assume the handler function would be differently named. Is passing in super-globals the right/best way to handle each request, or would it be sensible to have some other abstraction there? (Whether a formal request object a la PSR-7 or something else.) To what extent would user-space code run this way have to think about concurrency, shared memory, persistent SQL connections, etc? Does it have any implications for fiber-using async code? Depending on the details, this could be like fibers but for 3rd party SAPIs (something about 4 people in the world actually care about directly, everyone else just uses Revolt, Amp, or React, but mostly it doesn't get used), or completely changing the way 90% of the market runs PHP, which means frameworks will likely adapt to use that model primarily or exclusively (ie, less of a need for a "compile" step as a generated container or dispatcher is just held in memory automatically already). The latter sounds exciting to me, but I'm not sure which is your intent, so I don't know if I'm going too far with it. :-) Please advise on what the implications would be for the non-SAPI-developing PHP devs out there. --Larry Garfield -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php
[PHP-DEV] RFC proposal: worker mode primitives for SAPIs
Hello and Merry Christmas! One of the main features of FrankenPHP is its worker mode, which lets you keep a PHP application in memory to handle multiple HTTP requests. Worker modes are becoming increasingly popular in the PHP world. Symfony (Runtime Component), Laravel (Octane), and many projects based on these frameworks (API Platform, Sulu...) now support a worker mode. In addition to FrankenPHP, projects such as RoadRunner and Swoole provide engines supporting worker modes. According to benchmarks, worker modes can improve the performance of PHP applications by up to 15 times. In addition to FrankenPHP, which is basically a SAPI for Go's integrated web server, a new generation of SAPIs is currently under development. Several SAPIs written in Rust (including one by the RoadRunner team) are currently under development. These SAPIs, along with existing SAPIs, could benefit from a shared infrastructure to build worker modes. The FrankenPHP code is written and should be easy to move around in PHP itself, to enable other SAPIs to use it. In addition to sharing code, maintenance, performance optimization, etc., the existence of a common infrastructure would standardize the way worker scripts are created and provide a high-level PHP API for writing worker scripts that work with all SAPIs that rely on this new feature. SAPIs will still have to handle fetching requests from the web server and pausing the worker to wait for new requests (in FrankenPHP, we use GoRoutines for this, in Rust or C, other primitives will have to be used), but almost everything else could be shared. For reference, here's the FrankenPHP code I propose to integrate into libphp: https://github.com/dunglas/frankenphp/blob/main/frankenphp.c#L245 The public API is documented here: https://frankenphp.dev/docs/worker/#custom-apps I'd like to hear what the community thinks about this. Would you be interested in this functionality in PHP? Should I work on an RFC? If there's interest, I can work on a patch. Cheers, -- Kévin Dunglas