forked from https://github.com/symfony/symfony
d6ccc4f3e1
This PR was merged into the 5.2-dev branch.
Discussion
----------
[Console] Rework the signal integration
| Q | A
| ------------- | ---
| Branch? | master
| Bug fix? | no
| New feature? | yes
| Deprecations? | no
| Tickets | refs https://github.com/symfony/symfony/pull/33729
| License | MIT
| Doc PR |
I updated the code to have a better design and DX:
* `SignalRegistry::$handlingSignals` is gone. This was a temporary data store to
bind signal to symfony event. This does not belong to the `SignalRegistry`. It
has been replaced by `Application::$signalsToDispatchEvent`. A method has been
added to edit this list `Application::setSignalsToDispatchEvent()`
* The default value for `Application::$signalsToDispatchEvent` is `SIGINT,
SIGTERM, SIGUSR1, SIGUSR2`. Theses defaults seems good enough for most of
application. for recall:
* `SIGINT`: CTRL+C
* `SIGTERM`: `kill PID`, this is what occurs when stopping a process with SystemD, upstart & co
* `SIGUSR1` and `SIGUSR2`: Signal for user space
* `Application::setSignalRegistry()` is gone. Now the Application always owns a
signal registry. Since it's a CLI, it's legit to always have support for
signals. A method has been added for convenience, and to register signal
handler manually from the command:
```php
$application->getSignalRegistry()->register(SIGINT, function ($signal) {
dump("Signal ($signal) caught");
});
```
* The interface `SignalableCommandInterface` has been added. When a command
implements this interface, the command is automatically called when a
registered signal has been caught
A note about the BC:
* If one register an handler before the Symfony ones, the Signal Registry keeps
existing registered handlers. The BC is kept ✅
* If one register an handler after the Symfony ones, it overrides the Symfony
behavior. Since the feature is new. the BC is kept ✅
---
So now, If one want to listen a signal, they have few options depending on the context:
* A global action is common to all commands (such as logging, enabling a
profiler (👋 blackfire.io)): Use a listener. With autoconfigure, the following
code is enough:
```php
class SignalSubscriber implements EventSubscriberInterface
{
private $logger;
public function __construct(LoggerInterface $logger = null)
{
$this->logger = $logger ?: new NullLogger();
}
public function handleSignal(ConsoleSignalEvent $event)
{
$signal = $event->getHandlingSignal();
$this->logger->debug('The application has been signaled', [
'signal' => $signal,
]);
}
public static function getSubscribedEvents()
{
return [
ConsoleEvents::SIGNAL => 'handleSignal',
];
}
}
```
* The command should react to a signal: Implements the interface:
```php
class SignalCommand extends Command implements SignalableCommandInterface
{
protected static $defaultName = 'signal';
private $shouldStop = false;
protected function execute(InputInterface $input, OutputInterface $output): int
{
$output->writeln('hello, I am '. getmypid());
for ($i=0; $i < 60; $i++) {
if ($this->shouldStop) {
break;
}
$output->write('.');
sleep(1);
}
$output->writeln('');
$output->writeln('bye');
return 0;
}
public function handleSignal(int $signal)
{
dump([__METHOD__, $signal]);
$this->shouldStop = true;
}
public function getSubscribedSignals(): array
{
return [SIGINT];
}
}
```
* The command should react differently to many event and/or one wants a full control on name of the method called
```php
class SignalCommand extends Command
{
protected static $defaultName = 'signal';
private $shouldStop = false;
protected function execute(InputInterface $input, OutputInterface $output): int
{
$this->getApplication()->getSignalRegistry()->register(SIGINT, [$this, 'stop']);
$this->getApplication()->getSignalRegistry()->register(SIGUSR1, [$this, 'enableBlackfire']);
$output->writeln('hello, I am '. getmypid());
for ($i=0; $i < 60; $i++) {
if ($this->shouldStop) {
break;
}
$output->write('.');
sleep(1);
}
$output->writeln('');
$output->writeln('bye');
return 0;
}
public function stop()
{
$this->shouldStop = true;
}
public function enableBlackfire()
{
// ...
}
}
```
ping @marie
Commits
-------
|
||
---|---|---|
.github | ||
src/Symfony | ||
.appveyor.yml | ||
.editorconfig | ||
.gitignore | ||
.php_cs.dist | ||
.travis.yml | ||
CHANGELOG-4.0.md | ||
CHANGELOG-4.1.md | ||
CHANGELOG-4.2.md | ||
CHANGELOG-4.3.md | ||
CHANGELOG-4.4.md | ||
CHANGELOG-5.0.md | ||
CHANGELOG-5.1.md | ||
CODE_OF_CONDUCT.md | ||
composer.json | ||
CONTRIBUTING.md | ||
CONTRIBUTORS.md | ||
LICENSE | ||
link | ||
phpunit | ||
phpunit.xml.dist | ||
README.md | ||
UPGRADE-5.0.md | ||
UPGRADE-5.1.md | ||
UPGRADE-5.2.md | ||
UPGRADE-6.0.md |
Symfony is a PHP framework for web and console applications and a set of reusable PHP components. Symfony is used by thousands of web applications (including BlaBlaCar.com and Spotify.com) and most of the popular PHP projects (including Drupal and Magento).
Installation
- Install Symfony with Composer (see requirements details).
- Symfony follows the semantic versioning strictly, publishes "Long Term Support" (LTS) versions and has a release process that is predictable and business-friendly.
Documentation
- Read the Getting Started guide if you are new to Symfony.
- Try the Symfony Demo application to learn Symfony in practice.
- Master Symfony with the Guides and Tutorials, the Components docs and the Best Practices reference.
Community
- Join the Symfony Community and meet other members at the Symfony events.
- Get Symfony support on Stack Overflow, Slack, IRC, etc.
- Follow us on GitHub, Twitter and Facebook.
- Read our Code of Conduct and meet the CARE Team.
Contributing
Symfony is an Open Source, community-driven project with thousands of contributors. Join them contributing code or contributing documentation.
Security Issues
If you discover a security vulnerability within Symfony, please follow our disclosure procedure.
About Us
Symfony development is sponsored by SensioLabs, led by the Symfony Core Team and supported by Symfony contributors.