Closed AlliBalliBaba closed 5 months ago
Interesting! Thank you for providing a minimal reproducer, that helps a ton.
I happen to be working on a php-src RFC for someone right now so I popped over to the pcntl extension to just take a quick gander. From the looks of it, it probably isn't compatible with FrankenPHP.
I'd have to actually debug it to figure out what is going on, but in theory this bug would happen on any ZTS build with this extension and multiple threads.
Thanks for looking into it @withinboredom This is unfortunate since some worker implementations like the one in laravel explicitly require you to have pcntl installed. I guess the workaround right now would be to just handle a lot of requests before gracefully restarting the worker. The chance for a server crash would then probably be very small.
Actually Laravel Octane only needs pcntl for the CLI SAPI... to start FrankenPHP. FrankenPHP itself doesn't need nor use pcntl.
It should be possible to install pcntl for CLI but not for FrankenPHP, and this should work for Octane.
Symfony Messenger may also require pcntl. In any case, without this extension I can’t run a project that uses message processing in batches (not sure if this is related)
https://symfony.com/doc/current/messenger.html#process-messages-by-batches
I'm using RabbitMQ, the following packages are installed:
symfony/messenger
symfony/doctrine-messenger
symfony/amqp-messenger
I also had strange crashes with a large number of messages. It's very sad if this is related
messenger-1 |
messenger-1 | In DispatchPcntlSignalListener.php line 24:
messenger-1 |
messenger-1 | [Symfony\Component\ErrorHandler\Error\UndefinedFunctionError]
messenger-1 | Attempted to call function "pcntl_signal_dispatch" from namespace "Symfony\
messenger-1 | Component\Messenger\EventListener".
messenger-1 |
messenger-1 |
messenger-1 | Exception trace:
messenger-1 | at /srv/app/vendor/symfony/messenger/EventListener/DispatchPcntlSignalListener.php:24
messenger-1 | Symfony\Component\Messenger\EventListener\DispatchPcntlSignalListener->onWorkerRunning() at /srv/app/vendor/symfony/event-dispatcher/Debug/WrappedListener.php:116
messenger-1 | Symfony\Component\EventDispatcher\Debug\WrappedListener->__invoke() at /srv/app/vendor/symfony/event-dispatcher/EventDispatcher.php:206
messenger-1 | Symfony\Component\EventDispatcher\EventDispatcher->callListeners() at /srv/app/vendor/symfony/event-dispatcher/EventDispatcher.php:56
messenger-1 | Symfony\Component\EventDispatcher\EventDispatcher->dispatch() at /srv/app/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:127
messenger-1 | Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher->dispatch() at /srv/app/vendor/symfony/messenger/Worker.php:132
messenger-1 | Symfony\Component\Messenger\Worker->run() at /srv/app/vendor/symfony/messenger/Command/ConsumeMessagesCommand.php:235
messenger-1 | Symfony\Component\Messenger\Command\ConsumeMessagesCommand->execute() at /srv/app/vendor/symfony/console/Command/Command.php:279
messenger-1 | Symfony\Component\Console\Command\Command->run() at /srv/app/vendor/symfony/console/Application.php:1049
messenger-1 | Symfony\Component\Console\Application->doRunCommand() at /srv/app/vendor/symfony/framework-bundle/Console/Application.php:125
messenger-1 | Symfony\Bundle\FrameworkBundle\Console\Application->doRunCommand() at /srv/app/vendor/symfony/console/Application.php:318
messenger-1 | Symfony\Component\Console\Application->doRun() at /srv/app/vendor/symfony/framework-bundle/Console/Application.php:79
messenger-1 | Symfony\Bundle\FrameworkBundle\Console\Application->doRun() at /srv/app/vendor/symfony/console/Application.php:169
messenger-1 | Symfony\Component\Console\Application->run() at /srv/app/vendor/symfony/runtime/Runner/Symfony/ConsoleApplicationRunner.php:49
messenger-1 | Symfony\Component\Runtime\Runner\Symfony\ConsoleApplicationRunner->run() at /srv/app/vendor/autoload_runtime.php:29
messenger-1 | require_once() at /srv/app/bin/console:15
messenger-1 |
messenger-1 | messenger:consume [-l|--limit LIMIT] [-f|--failure-limit FAILURE-LIMIT] [-m|--memory-limit MEMORY-LIMIT] [-t|--time-limit TIME-LIMIT] [--sleep SLEEP] [-b|--bus BUS] [--queues QUEUES] [--no-reset] [--] [<receivers>...]
@lermontex it's the same situation for Symfony Messenger. pcntl is only needed to run the consumer command (CLI), FrankenPHP (with the notable exception of the php-cli
subcommand) runs the web server.
You could run the commands with the standard PHP CLI SAPI, (the php
binary) with pcntl installed, and the web server (the FrankenPHP SAPI) without pcntl.
That being said, this is just a workaround. The real solution is to fix the thread safety issue in pcntl.
Could you please report this bug to PHP directly, as this doesn't look specific to FrankenPHP (and there is nothing we can do about that in this code base).
@dunglas, The fact is that, as far as I understand, using dunglas/symfony-docker I will have to add an additional image for Messenger
I'm currently using one image to run the webserver and handler. A similar solution is described here https://github.com/dunglas/symfony-docker/issues/539
I think it should be mentioned that this may cause errors since the pcntl
extension will be installed in any mode:
https://github.com/dunglas/symfony-docker/blob/bfdd75e73ffcdce57f0f9f883029b57629549195/Dockerfile#L28
RUN set -eux; \
install-php-extensions \
@composer \
apcu \
intl \
opcache \
zip \
pcntl \
;
root@api:/srv/app# php -m
[PHP Modules]
amqp
apcu
Core
ctype
curl
date
dom
fileinfo
filter
hash
iconv
intl
json
libxml
mbstring
mysqlnd
openssl
pcntl
pcre
PDO
pdo_pgsql
pdo_sqlite
Phar
posix
random
readline
Reflection
session
SimpleXML
sodium
SPL
sqlite3
standard
tokenizer
xml
xmlreader
xmlwriter
Zend OPcache
zip
zlib
[Zend Modules]
Zend OPcache
Anyway, it seems we need to add information about incompatibility (if this is indeed the case) to the documentation
@lermontex we can document it in the "known issues" page! PR welcome.
Thanks to the reproducer, this bug shouldn't be too hard to fix.
I have a very busy week (and the next will be busy too), but I'll try to take a look after that if someone didn't had time to work on this.
@dunglas, Unfortunately, I will not be able to provide more specific information, since I was never able to find out why the errors occurred in my case. I just mentioned that incompatibility with pcntl can also affect the operation of Symfony Messenger. Hope this can prevent unexpected errors and improve comppatiblity in the future
Anyway, thanks for your work!
You could run the commands with the standard PHP CLI SAPI, (the php binary) with pcntl installed, and the web server (the FrankenPHP SAPI) without pcntl.
You can do this by using different php.ini
files instead of different containers. Basically have a web.php.ini
and a worker.php.ini
. In theory, you should already be doing this because workers generally need more memory than web requests, different error reporting, potentially different extensions enabled, different opcache/jit config, etc.
I've noticed that triggering gc_collect_cycles()
at the end of the worker script also seems to mitigate crashes, at least with a Laravel project I'm working on. I created an according PR for Laravel Octane. It would be nice if this also fixes crashes other people have been having.
The main problem with these types of crashes is how hard they are to reproduce
Thanks for the reproducer. I can reproduce the bug on Mac using the latest version. I'm on it.
https://github.com/dunglas/frankenphp/pull/857 fixes the problem on my side. I don't think that it's related to pcntl.
Could you try this patch to see if it fixes the issue for you too @AlliBalliBaba?
I suspect it will fix the issue. I'll try installing from source if I have time or with a new release once it's out
I can confirm that v1.2.1 does indeed fix the bug.
What happened?
I am seeing weird server crashes in the
dunglas/frankenphp:1.1-php8.3-bookworm
anddunglas/frankenphp:1.1-php8.3-alpine
images if thepcntl
extension is also installed.The Frankenphp worker server will crash when uploading a multipart/form-data image and then redirecting afterwards. The issue seems to stem from some memory misallocation. The bug seems to happen consistently when the worker only handles 1 request. For reproducing this minimal example, you have to create a
frankenphp-worker.php
with the following content:To get the server crash, I had to do the following:
(dunglas/frankenphp:1.1-php8.3-bookworm)
install-php-extensions pcntl
)It is also weird that this is not 100% consistent.
I recorded this bug in Ubuntu (WSL) (amd) in both the
dunglas/frankenphp:1.1-php8.3-bookworm
anddunglas/frankenphp:1.1-php8.3-alpine
docker images. But -only- if thepcntl
extension is also installed so maybe there's an incompatiblity there? It feels very randomAlso when the bug occurs (inconsistently) I see either
free(): invalid pointer
in the output before the POST request is handled ordouble free or corruption (out)
after the request is handled.Build Type
Docker (Debian Bookworm)
Worker Mode
Yes
Operating System
GNU/Linux
CPU Architecture
x86_64
PHP configuration
Relevant log output