This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
Go to file
Fabien Potencier d6ccc4f3e1 feature #37827 [Console] Rework the signal integration (lyrixx)
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
-------

df57119884 [Console] Rework the signal integration
2020-08-13 18:08:21 +02:00
.github Merge branch '4.4' into 5.1 2020-07-29 16:51:18 +02:00
src/Symfony [Console] Rework the signal integration 2020-08-13 17:50:47 +02:00
.appveyor.yml Merge branch '5.0' 2020-04-12 11:49:11 +02:00
.editorconfig Update .editorconfig 2018-09-06 16:22:56 +02:00
.gitignore Run the phpunit-bridge from a PR 2019-08-02 17:46:19 +02:00
.php_cs.dist [Serializer] Add CompiledClassMetadataFactory 2020-08-11 12:10:04 +02:00
.travis.yml clean up HHVM instructions 2020-07-08 16:52:52 +02:00
CHANGELOG-4.0.md Merge branch '3.4' into 4.1 2018-08-01 18:22:14 +02:00
CHANGELOG-4.1.md updated CHANGELOG for 4.1.10 2019-01-06 17:16:07 +01:00
CHANGELOG-4.2.md updated CHANGELOG for 4.2.10 2019-06-26 16:19:37 +02:00
CHANGELOG-4.3.md updated CHANGELOG for 4.3.10 2020-01-21 14:13:32 +01:00
CHANGELOG-4.4.md Update CHANGELOG for 4.4.11 2020-07-24 06:09:57 +02:00
CHANGELOG-5.0.md Merge branch '5.0' into 5.1 2020-06-15 13:50:15 +02:00
CHANGELOG-5.1.md Update CHANGELOG for 5.1.3 2020-07-24 06:22:46 +02:00
CODE_OF_CONDUCT.md Added the Code of Conduct file 2018-10-10 03:13:30 -07:00
composer.json Add Beanstalkd Messenger bridge 2020-08-13 09:43:16 +02:00
CONTRIBUTING.md Mention the community review guide 2016-12-18 22:02:35 +01:00
CONTRIBUTORS.md update CONTRIBUTORS for 3.4.43 2020-07-24 05:48:58 +02:00
LICENSE Update year in license files 2020-01-01 12:03:25 +01:00
link Add new packages on the link script 2020-03-04 17:45:35 +01:00
phpunit Use PHPUnit 9.3 on php 8. 2020-08-10 10:16:22 +02:00
phpunit.xml.dist [Uid] minor improvements 2020-03-20 20:42:05 +01:00
README.md Minor improvement 2020-07-29 07:57:47 +02:00
UPGRADE-5.0.md Typo: somes styles fixed 2020-08-06 09:00:23 +02:00
UPGRADE-5.1.md Added deprecation for RememberMe services without logout() method 2020-05-16 13:05:23 +02:00
UPGRADE-5.2.md feature #36691 [FrameworkBundle] Deprecate some public services to private (fancyweb) 2020-07-31 09:12:35 +02:00
UPGRADE-6.0.md [FrameworkBundle] Deprecate some public services to private 2020-07-03 10:46:50 +02:00

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

Documentation

Community

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.