Closed
Description
Symfony version(s) affected
5.2+
Description
The (awesome) console signal handling introduced in #33729 and #37827 seems to have some issues (or maybe it's just me 😺 ) with subscriber events:
- Subscriber
ConsoleEvents::SIGNAL
events do not get called, but events such asConsoleEvents::TERMINATE
do - Listener events (command implementing
SignalableCommandInterface
) work, with one caveat;- if a subscriber exists, it will be called and the command's discrete handler ignored
How to reproduce
-
Create a Symfony project
symfony new --webapp symfony-pcntl-test
-
Build the following classes
// src/Command/AbstractSignalCommand.php
abstract class AbstractSignalCommand extends Command
{
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$io->title("Starting {$this->getName()} command execution");
for ($i = 0; $i <10; ++$i) {
$io->writeln('Tick ' . $i);
sleep(1);
}
$io->success('Normal exit from command.');
return Command::SUCCESS;
}
}
// src/Command/SignalListenerCommand.php
#[AsCommand(
name: 'app:signal:listener',
)]
class SignalListenerCommand extends AbstractSignalCommand implements SignalableCommandInterface
{
public function getSubscribedSignals(): array
{
return [SIGINT];
}
public function handleSignal(int $signal): void
{
if (SIGINT === $signal) {
dump('Caught a listener SIGINT');
exit;
}
}
}
// src/Command/SignalSubscriberCommand.php
#[AsCommand(
name: 'app:signal:subscriber',
)]
class SignalSubscriberCommand extends AbstractSignalCommand
{
}
// src/EventSubscriber/CommandSignalSubscriber.php
class CommandSignalSubscriber implements EventSubscriberInterface
{
public function onConsoleSignal(ConsoleSignalEvent $event): void
{
if ($event->getHandlingSignal() === SIGINT) {
dump('Caught a !!!subscriber!!! SIGINT');
exit;
}
}
public function onConsoleTerminate(ConsoleTerminateEvent $event)
{
dump('Handling normal termination event');
}
public static function getSubscribedEvents(): array
{
return [
ConsoleEvents::SIGNAL => 'onConsoleSignal',
ConsoleEvents::TERMINATE => 'onConsoleTerminate',
];
}
}
- Check event dispatcher
$ bin/console debug:event-dispatcher console.signal
# ...
------- ---------------------------------------------------------------- ----------
Order Callable Priority
------- ---------------------------------------------------------------- ----------
#1 App\EventSubscriber\CommandSignalSubscriber::onConsoleSignal() 0
------- ---------------------------------------------------------------- -----------
- Run the listener enabled command and emit a CTRL+c
$ bin/console app:signal:listener
Starting app:signal:listener command execution
==============================================
Tick 0
Tick 1
^C"Caught a !!!subscriber!!! SIGINT"
NOTE: The handling of the signal is done in the subscriber here, but removing ConsoleEvents::SIGNAL
from CommandSignalSubscriber::getSubscribedEvents
will cause the handling to be done by the listener.
- Run the subscriber enabled command and emit a CTRL+c
$ bin/console app:signal:subscriber
Starting app:signal:subscriber command execution
================================================
Tick 0
Tick 1
^C
NOTE: Nothing handles the signal.
Possible Solution
No response
Additional Context
- Tested on Symfony v6.0.4