Worker configuration example for CakePHP ^4
Describe you feature request
Is your feature request related to a problem? Please describe. I've started working on a worker configuration example for CakePHP ^4 based on previous work done for RoadRunner here https://github.com/CakeDC/cakephp-roadrunner but I'm struggling a bit understanding how to integrate it with the \frankenphp_handle_request as it seems to "work with the defaults" even if I define an application previously.
Describe the solution you'd like Do you have already a working configuration I could use as a default, apart from the one located here https://frankenphp.dev/docs/worker/ in Custom Apps?
Describe alternatives you've considered I went through other workers to check the implementation, given the fact that CakePHP is PSR 7 and 15 compatible, the solution should be close to others implemented...
If you know of a working repo or configuration I could use as a starting point, I would be grateful, thank you!
FrankenPHP uses the same globals as a regular PHP request, so you can probably just call createFromGlobals when creating a new request. The only other worker implementations I know are the one from Symfony Runtime and Laravel Octane. Laravel's implementation does a lot of global state resetting between requests. I'd say the less the framework depends on various global state, the easier it is to implement a worker mode.
Thank you, I'll prepare some code...
My first approach to understand the worker mode:
<?php
use Cake\Http\ResponseEmitter;
ignore_user_abort(true);
require __DIR__.'/vendor/autoload.php';
$myApp = new \App\Application(__DIR__ . '/config');
$myApp->bootstrap();
$myApp->pluginBootstrap();
error_log('Worker started');
$responseEmitter = new ResponseEmitter();
$handler = static function () use ($myApp, $responseEmitter) {
error_log('Worker handler');
$request = \Cake\Http\ServerRequestFactory::fromGlobals();
$response = $myApp->handle($request);
$responseEmitter->emit($response);
};
$maxRequests = (int)($_SERVER['MAX_REQUESTS'] ?? 0);
for ($nbRequests = 0; !$maxRequests || $nbRequests < $maxRequests; ++$nbRequests) {
error_log('Worker handling request');
$keepRunning = \frankenphp_handle_request($handler);
gc_collect_cycles();
if (!$keepRunning) break;
}
I've added an error_log trace into my Application::bootstrap method, I was assuming the bootstrap should NOT be called in each request, as the code inside the handler is not calling it, but it's being called...
I'm using a simple Dockerfile
FROM dunglas/frankenphp:1-php8.2
# Be sure to replace "your-domain-name.example.com" by your domain name
ENV SERVER_NAME=localhost
# If you want to disable HTTPS, use this value instead:
#ENV SERVER_NAME=:80
# Enable PHP production settings
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
RUN install-php-extensions \
pdo_mysql \
intl \
zip \
opcache
# Copy the PHP files of your project in the public directory
COPY . /app
And the commands
docker build -t my-php-app .
docker run -v $PWD:/app/public -p 80:80 -p 443:443 -p 443:443/udp -e FRANKENPHP_CONFIG="worker ./worker.php" --tty my-php-app
Am I under the correct assumption that the code in the Application::bootstrap should not be called in each request handling?
Thank you,
Yeah bootstrap should only be called once per $maxRequests iterations, unless the worker crashes somehow through a fatal error.
I'll try your script when I have time.
FrankenPHP was fully integrated with CakePHP here https://github.com/cakephp/cakephp/pull/18694 and will be available as soon as v5.3.0 will be released.