diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ecda4d..6aeb4c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## 0.2.0 + +- Add support for Symfony 7 +- Add `frankenphp_loop_max` option +- Drop support for PHP 8.0 + ## 0.1.0 First version diff --git a/README.md b/README.md index 3f030a7..1dd5341 100644 --- a/README.md +++ b/README.md @@ -36,3 +36,7 @@ return function (array $context) { return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']); }; ``` + +## Options + +* `frankenphp_loop_max`: the number of requests after which the worker must restart, to prevent weird memory leaks (default to `500`, set to `-1` to never restart) diff --git a/composer.json b/composer.json index 959bc01..e389bf8 100644 --- a/composer.json +++ b/composer.json @@ -10,10 +10,10 @@ } ], "require": { - "php": ">=8.0", - "symfony/dependency-injection": "^5.4 || ^6.0", - "symfony/http-kernel": "^5.4 || ^6.0", - "symfony/runtime": "^5.4 || ^6.0" + "php": ">=8.1", + "symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0", + "symfony/http-kernel": "^5.4 || ^6.0 || ^7.0", + "symfony/runtime": "^5.4 || ^6.0 || ^7.0" }, "require-dev": { "phpunit/phpunit": "^9.5" diff --git a/src/Runner.php b/src/Runner.php index 46c8378..afb704d 100644 --- a/src/Runner.php +++ b/src/Runner.php @@ -16,31 +16,47 @@ */ class Runner implements RunnerInterface { - private HttpKernelInterface $kernel; - - public function __construct(HttpKernelInterface $kernel) - { - $this->kernel = $kernel; + public function __construct( + private HttpKernelInterface $kernel, + private int $loopMax, + ) { } public function run(): int { + // Prevent worker script termination when a client connection is interrupted + ignore_user_abort(true); + + $xdebugConnectToClient = function_exists('xdebug_connect_to_client'); + $server = array_filter($_SERVER, static fn (string $key) => !str_starts_with($key, 'HTTP_'), ARRAY_FILTER_USE_KEY); - do { - $ret = \frankenphp_handle_request(function () use ($server, &$sfRequest, &$sfResponse): void { - // Merge the environment variables coming from DotEnv with the ones tight to the current request - $_SERVER += $server; + $server['APP_RUNTIME_MODE'] = 'web=1&worker=1'; - $sfRequest = Request::createFromGlobals(); - $sfResponse = $this->kernel->handle($sfRequest); + $handler = function () use ($server, &$sfRequest, &$sfResponse, $xdebugConnectToClient): void { + // Connect to the Xdebug client if it's available + if ($xdebugConnectToClient) { + xdebug_connect_to_client(); + } - $sfResponse->send(); - }); + // Merge the environment variables coming from DotEnv with the ones tied to the current request + $_SERVER += $server; + + $sfRequest = Request::createFromGlobals(); + $sfResponse = $this->kernel->handle($sfRequest); + + $sfResponse->send(); + }; + + $loops = 0; + do { + $ret = \frankenphp_handle_request($handler); if ($this->kernel instanceof TerminableInterface && $sfRequest && $sfResponse) { $this->kernel->terminate($sfRequest, $sfResponse); } - } while ($ret); + + gc_collect_cycles(); + } while ($ret && (-1 === $this->loopMax || ++$loops < $this->loopMax)); return 0; } diff --git a/src/Runtime.php b/src/Runtime.php index e45cb3f..efae98b 100644 --- a/src/Runtime.php +++ b/src/Runtime.php @@ -15,10 +15,22 @@ */ class Runtime extends SymfonyRuntime { + /** + * @param array{ + * frankenphp_loop_max?: int, + * } $options + */ + public function __construct(array $options = []) + { + $options['frankenphp_loop_max'] = (int) ($options['frankenphp_loop_max'] ?? $_SERVER['FRANKENPHP_LOOP_MAX'] ?? $_ENV['FRANKENPHP_LOOP_MAX'] ?? 500); + + parent::__construct($options); + } + public function getRunner(?object $application): RunnerInterface { if ($application instanceof HttpKernelInterface && ($_SERVER['FRANKENPHP_WORKER'] ?? false)) { - return new Runner($application); + return new Runner($application, $this->options['frankenphp_loop_max']); } return parent::getRunner($application); diff --git a/tests/RunnerTest.php b/tests/RunnerTest.php index 8993114..8d3caa7 100644 --- a/tests/RunnerTest.php +++ b/tests/RunnerTest.php @@ -37,7 +37,7 @@ public function testRun(): void $_SERVER['FOO'] = 'bar'; - $runner = new Runner($application); + $runner = new Runner($application, 500); $this->assertSame(0, $runner->run()); } }