Skip to content
This repository has been archived by the owner on Jan 17, 2022. It is now read-only.

Commit

Permalink
feat(server): handle signals to enable graceful termination
Browse files Browse the repository at this point in the history
  • Loading branch information
k911 committed Apr 17, 2021
1 parent 8793695 commit e738805
Show file tree
Hide file tree
Showing 36 changed files with 977 additions and 79 deletions.
8 changes: 5 additions & 3 deletions .php_cs.dist
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ declare(strict_types=1);

$finder = PhpCsFixer\Finder::create()
->in(['src', 'tests'])
->exclude(['Fixtures/Symfony/app/var']);
->exclude(['Fixtures/Symfony/app/var'])
;

/**
/*
* @see https://github.com/FriendsOfPHP/PHP-CS-Fixer for rules
*/
return PhpCsFixer\Config::create()
Expand Down Expand Up @@ -42,4 +43,5 @@ return PhpCsFixer\Config::create()
'php_unit_test_case_static_method_calls' => ['call_type' => 'self'],
])
->setRiskyAllowed(true)
->setFinder($finder);
->setFinder($finder)
;
30 changes: 15 additions & 15 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@
"ext-json": "*",
"ext-swoole": "^4.5.10",
"beberlei/assert": "^3.0",
"symfony/config": "^4.3.1|^5.0",
"symfony/console": "^4.3.1|^5.0",
"symfony/dependency-injection": "^4.3.1|^5.0",
"symfony/http-foundation": "^4.3.1|^5.0",
"symfony/http-kernel": "^4.3.1|^5.0",
"symfony/process": "^4.3.1|^5.0"
"symfony/config": "^4.4.0|^5.0",
"symfony/console": "^4.4.0|^5.0",
"symfony/dependency-injection": "^4.4.0|^5.0",
"symfony/http-foundation": "^4.4.0|^5.0",
"symfony/http-kernel": "^4.4.0|^5.0",
"symfony/process": "^4.4.0|^5.0"
},
"require-dev": {
"doctrine/annotations": "^1.6",
Expand All @@ -45,15 +45,15 @@
"phpunit/phpunit": "^9.1.3",
"swoole/ide-helper": "^4.5.10",
"symfony/debug-pack": "^1.0",
"symfony/error-handler": "^4.3.1|^5.0",
"symfony/framework-bundle": "^4.3.1|^5.0",
"symfony/messenger": "^4.3.1|^5.0",
"symfony/monolog-bridge": "^4.3.1|^5.0",
"symfony/error-handler": "^4.4.0|^5.0",
"symfony/framework-bundle": "^4.4.0|^5.0",
"symfony/messenger": "^4.4.0|^5.0",
"symfony/monolog-bridge": "^4.4.0|^5.0",
"symfony/monolog-bundle": "^3.3",
"symfony/profiler-pack": "^1.0",
"symfony/twig-bundle": "^4.3.1|^5.0",
"symfony/var-dumper": "^4.3.1|^5.0",
"symfony/yaml": "^4.3.1|^5.0",
"symfony/twig-bundle": "^4.4.0|^5.0",
"symfony/var-dumper": "^4.4.0|^5.0",
"symfony/yaml": "^4.4.0|^5.0",
"upscale/swoole-blackfire": "^3.0"
},
"suggest": {
Expand Down Expand Up @@ -82,10 +82,10 @@
"php tests/Fixtures/Symfony/app/console --ansi"
],
"static-analyse-src": [
"phpstan analyze src -l 7 -c phpstan.neon.dist --ansi --memory-limit=512M"
"phpstan analyze -c phpstan.neon.dist --ansi --memory-limit=512M"
],
"static-analyse-tests": [
"phpstan analyze tests -l 4 -c phpstan.tests.neon --ansi --memory-limit=512M"
"phpstan analyze -c phpstan.tests.neon --ansi --memory-limit=512M"
],
"cs-analyse": [
"php-cs-fixer fix -v --dry-run --diff --stop-on-violation --ansi"
Expand Down
2 changes: 1 addition & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
parameters:
level: 7
inferPrivatePropertyTypeFromConstructor: true
checkMissingIterableValueType: false
excludes_analyse:
Expand All @@ -8,3 +9,5 @@ parameters:
- src/Server/WorkerHandler/HMRWorkerStartHandler.php
ignoreErrors:
# Put false positives here
paths:
- src
3 changes: 3 additions & 0 deletions phpstan.tests.neon
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
parameters:
level: 4
inferPrivatePropertyTypeFromConstructor: true
checkMissingIterableValueType: false
excludes_analyse:
Expand All @@ -13,3 +14,5 @@ parameters:

# Symfony configuration files
- '#Variable \$container might not be defined#'
paths:
- tests
38 changes: 22 additions & 16 deletions src/Bridge/Symfony/Bundle/Command/AbstractServerStartCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
use function K911\Swoole\decode_string_as_set;
use function K911\Swoole\format_bytes;
use function K911\Swoole\get_max_memory;
use K911\Swoole\Process\Signal\PcntlSignalHandler;
use K911\Swoole\Process\Signal\Signal;
use K911\Swoole\Server\Config\Socket;
use K911\Swoole\Server\Configurator\ConfiguratorInterface;
use K911\Swoole\Server\HttpServer;
Expand All @@ -25,33 +27,28 @@

abstract class AbstractServerStartCommand extends Command
{
/**
* @var ParameterBagInterface
*/
protected $parameterBag;

private $server;
private $bootManager;
private $serverConfiguration;
private $serverConfigurator;

/**
* @var bool
*/
private $testing = false;
protected ParameterBagInterface $parameterBag;
private HttpServer $server;
private BootableInterface $bootManager;
private HttpServerConfiguration $serverConfiguration;
private ConfiguratorInterface $serverConfigurator;
private ?PcntlSignalHandler $pcntlSignalHandler;
private bool $testing = false;

public function __construct(
HttpServer $server,
HttpServerConfiguration $serverConfiguration,
ConfiguratorInterface $serverConfigurator,
ParameterBagInterface $parameterBag,
BootableInterface $bootManager
BootableInterface $bootManager,
?PcntlSignalHandler $pcntlSignalHandler
) {
$this->server = $server;
$this->bootManager = $bootManager;
$this->parameterBag = $parameterBag;
$this->serverConfigurator = $serverConfigurator;
$this->serverConfiguration = $serverConfiguration;
$this->pcntlSignalHandler = $pcntlSignalHandler;

parent::__construct();
}
Expand Down Expand Up @@ -201,7 +198,7 @@ protected function prepareConfigurationRowsToPrint(HttpServerConfiguration $serv
['worker_count', $serverConfiguration->getWorkerCount()],
['reactor_count', $serverConfiguration->getReactorCount()],
['worker_max_request', $serverConfiguration->getMaxRequest()],
['worker_max_request_grace', $serverConfiguration->getMaxRequestGrace()],
['worker_max_request_grace', $serverConfiguration->getMaxRequestGrace() ?? '~'],
['memory_limit', format_bytes(get_max_memory())],
['trusted_hosts', \implode(', ', $runtimeConfiguration['trustedHosts'])],
];
Expand All @@ -226,6 +223,15 @@ protected function startServer(HttpServerConfiguration $serverConfiguration, Htt
{
$io->comment('Quit the server with CONTROL-C.');

if ($this->pcntlSignalHandler instanceof PcntlSignalHandler && $serverConfiguration->isReactorRunningMode()) {
// Register dummy SIGINT handler to make sure process doesn't exit to early when CONTROL-C is hit
$this->pcntlSignalHandler->register(function () use ($server): void {
if (\getmypid() !== $server->getMasterPid()) {
$server->shutdown();
}
}, Signal::int());
}

if ($server->start()) {
$io->newLine();
$io->success('Swoole HTTP Server has been successfully shutdown.');
Expand Down
23 changes: 23 additions & 0 deletions src/Bridge/Symfony/Bundle/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@ public function getConfigTreeBuilder(): TreeBuilder
->booleanNode('debug_handler')
->defaultNull()
->end()
->booleanNode('reactor_mode_graceful_signal_handler')
->defaultFalse()
->treatNullLike(false)
->end()
->booleanNode('trust_all_proxies_handler')
->defaultFalse()
->treatNullLike(false)
Expand All @@ -206,6 +210,18 @@ public function getConfigTreeBuilder(): TreeBuilder
->end()
->end()
->end() // drivers
->arrayNode('coroutine')
->addDefaultsIfNotSet()
->canBeDisabled()
->children()
->arrayNode('hooks')
->defaultValue(['all'])
->prototype('enum')
->values(['off', 'all'])
->end()
->end()
->end()
->end()
->arrayNode('settings')
->addDefaultsIfNotSet()
->children()
Expand Down Expand Up @@ -240,6 +256,13 @@ public function getConfigTreeBuilder(): TreeBuilder
->min(0)
->defaultValue(0)
->end()
->booleanNode('worker_reload_async')
->defaultTrue()
->end()
->integerNode('worker_exit_timeout_seconds')
->min(0)
->defaultValue(5)
->end()
->scalarNode('worker_max_request_grace')
->defaultNull()
->end()
Expand Down
38 changes: 38 additions & 0 deletions src/Bridge/Symfony/Bundle/DependencyInjection/SwooleExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@
use K911\Swoole\Bridge\Symfony\Messenger\SwooleServerTaskTransportFactory;
use K911\Swoole\Bridge\Symfony\Messenger\SwooleServerTaskTransportHandler;
use K911\Swoole\Bridge\Upscale\Blackfire\WithProfiler;
use K911\Swoole\Process\Signal\PcntlSignalHandler;
use K911\Swoole\Server\Config\Socket;
use K911\Swoole\Server\Config\Sockets;
use K911\Swoole\Server\Configurator\ConfiguratorInterface;
use K911\Swoole\Server\Configurator\WithProcess;
use K911\Swoole\Server\HttpServer;
use K911\Swoole\Server\HttpServerConfiguration;
use K911\Swoole\Server\RequestHandler\AdvancedStaticFilesServer;
Expand All @@ -32,10 +34,13 @@
use K911\Swoole\Server\Runtime\HMR\HotModuleReloaderInterface;
use K911\Swoole\Server\Runtime\HMR\InotifyHMR;
use K911\Swoole\Server\TaskHandler\TaskHandlerInterface;
use K911\Swoole\Server\WorkerHandler\ClearAllTimersWorkerExitHandler;
use K911\Swoole\Server\WorkerHandler\HMRWorkerStartHandler;
use K911\Swoole\Server\WorkerHandler\WorkerExitHandlerInterface;
use K911\Swoole\Server\WorkerHandler\WorkerStartHandlerInterface;
use ReflectionMethod;
use RuntimeException;
use Swoole\Process;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
Expand Down Expand Up @@ -192,6 +197,8 @@ private function registerHttpServerConfiguration(array $config, ContainerBuilder
'socket_type' => $socketType,
'ssl_enabled' => $sslEnabled,
'settings' => $settings,
'coroutine' => $coroutine,
'services' => $services,
] = $config;

if ('auto' === $static['strategy']) {
Expand All @@ -211,6 +218,8 @@ private function registerHttpServerConfiguration(array $config, ContainerBuilder

$settings['serve_static'] = $static['strategy'];
$settings['public_dir'] = $static['public_dir'];
$settings['coroutine_enabled'] = $coroutine['enabled'];
$settings['coroutine_hooks'] = $coroutine['hooks'];

if ('auto' === $settings['log_level']) {
$settings['log_level'] = $this->isDebug($container) ? 'debug' : 'notice';
Expand All @@ -234,9 +243,31 @@ private function registerHttpServerConfiguration(array $config, ContainerBuilder
->addArgument($settings)
;

if ('reactor ' === $runningMode && $services['reactor_mode_graceful_signal_handler']) {
$this->registerReactorGracefulSignalHandler($container);
}

$this->registerHttpServerHMR($hmr, $container);
}

private function registerReactorGracefulSignalHandler(ContainerBuilder $container): void
{
if (\extension_loaded('pcntl') && \extension_loaded('posix')) {
$container->register(PcntlSignalHandler::class);
}

$container->register('swoole_bundle.server.http_server.configurator.with_process_signal_shutdown_handler')
->setClass(WithProcess::class)
->setAutowired(false)
->setAutoconfigured(false)
->setPublic(false)
->setArguments([Process::class => new Reference('swoole_bundle.http_server.runtime.server_shutdown.signal_handler_swoole_process')])
;

$def = $container->getDefinition('swoole_bundle.server.http_server.configurator.for_server_run_command');
$def->addArgument(new Reference('swoole_bundle.server.http_server.configurator.with_process_signal_shutdown_handler'));
}

private function registerHttpServerHMR(string $hmr, ContainerBuilder $container): void
{
if ('off' === $hmr || !$this->isDebug($container)) {
Expand All @@ -255,6 +286,13 @@ private function registerHttpServerHMR(string $hmr, ContainerBuilder $container)
->setArgument('$decorated', new Reference(HMRWorkerStartHandler::class.'.inner'))
->setDecoratedService(WorkerStartHandlerInterface::class)
;

$container->autowire(ClearAllTimersWorkerExitHandler::class)
->setPublic(false)
->setAutoconfigured(true)
->setArgument('$decorated', new Reference(ClearAllTimersWorkerExitHandler::class.'.inner'))
->setDecoratedService(WorkerExitHandlerInterface::class)
;
}

private function resolveAutoHMR(): string
Expand Down
33 changes: 31 additions & 2 deletions src/Bridge/Symfony/Bundle/Resources/config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,31 @@ services:

K911\Swoole\Server\RequestHandler\LimitedRequestHandler:

K911\Swoole\Server\LifecycleHandler\SigIntHandler:
K911\Swoole\Server\Runtime\ServerShutdown\SignalServerShutdownHandlerOnServerStart:

K911\Swoole\Component\Clock\ClockInterface:
class: K911\Swoole\Component\Clock\CoroutineFriendlyClock

K911\Swoole\Process\Signal\SwooleProcessSignalHandler:

K911\Swoole\Process\ProcessFactory:

K911\Swoole\Process\ProcessManagerInterface:
class: K911\Swoole\Process\ProcessManager

K911\Swoole\Process\Signal\SignalHandlerInterface:
alias: K911\Swoole\Process\Signal\SwooleProcessSignalHandler

swoole_bundle.http_server.runtime.server_shutdown.signal_handler_process:
class: K911\Swoole\Server\Runtime\ServerShutdown\SignalServerShutdownHandlerAsServerProcess

swoole_bundle.http_server.runtime.server_shutdown.signal_handler_swoole_process:
class: Swoole\Process
factory: ['@K911\Swoole\Process\ProcessFactory', make]
autowire: false
autoconfigure: false
arguments:
$process: '@swoole_bundle.http_server.runtime.server_shutdown.signal_handler_process'

K911\Swoole\Server\Runtime\CallableBootManagerFactory:

Expand All @@ -76,6 +100,9 @@ services:
K911\Swoole\Server\WorkerHandler\WorkerStartHandlerInterface:
class: K911\Swoole\Server\WorkerHandler\NoOpWorkerStartHandler

K911\Swoole\Server\WorkerHandler\WorkerExitHandlerInterface:
class: K911\Swoole\Server\WorkerHandler\NoOpWorkerExitHandler

K911\Swoole\Server\LifecycleHandler\ServerStartHandlerInterface:
class: K911\Swoole\Server\LifecycleHandler\NoOpServerStartHandler

Expand Down Expand Up @@ -123,6 +150,8 @@ services:

K911\Swoole\Server\Configurator\WithWorkerStartHandler:

K911\Swoole\Server\Configurator\WithWorkerExitHandler:

K911\Swoole\Server\Configurator\WithTaskHandler:

K911\Swoole\Server\Configurator\WithTaskFinishedHandler:
Expand Down Expand Up @@ -164,4 +193,4 @@ services:
class: K911\Swoole\Server\Configurator\WithServerStartHandler
autoconfigure: false
arguments:
$handler: '@K911\Swoole\Server\LifecycleHandler\SigIntHandler'
$handler: '@K911\Swoole\Server\Runtime\ServerShutdown\SignalServerShutdownHandlerOnServerStart'
10 changes: 10 additions & 0 deletions src/Client/HttpClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ public function __construct(Client $client)
$this->client = $client;
}

public function __destruct()
{
$this->close();
}

public function close(): void
{
$this->client->close();
}

public static function fromSocket(Socket $socket, array $options = []): self
{
return self::fromDomain(
Expand Down
Loading

0 comments on commit e738805

Please sign in to comment.