Skip to content

Commit b8474c7

Browse files
committed
[Console] Register signal handling only for commands implemeting SignalableCommandInterface
Actually, it does not make sens to listen all signals for all commands. This commit also add more test for this part of code.
1 parent 4f00061 commit b8474c7

File tree

2 files changed

+82
-17
lines changed

2 files changed

+82
-17
lines changed

Application.php

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -286,23 +286,6 @@ public function doRun(InputInterface $input, OutputInterface $output)
286286
$command = $this->find($alternative);
287287
}
288288

289-
if ($this->dispatcher && $this->signalRegistry) {
290-
foreach ($this->signalsToDispatchEvent as $signal) {
291-
$event = new ConsoleSignalEvent($command, $input, $output, $signal);
292-
293-
$this->signalRegistry->register($signal, function ($signal, $hasNext) use ($event) {
294-
$this->dispatcher->dispatch($event, ConsoleEvents::SIGNAL);
295-
296-
// No more handlers, we try to simulate PHP default behavior
297-
if (!$hasNext) {
298-
if (!\in_array($signal, [\SIGUSR1, \SIGUSR2], true)) {
299-
exit(0);
300-
}
301-
}
302-
});
303-
}
304-
}
305-
306289
$this->runningCommand = $command;
307290
$exitCode = $this->doRunCommand($command, $input, $output);
308291
$this->runningCommand = null;
@@ -961,6 +944,24 @@ protected function doRunCommand(Command $command, InputInterface $input, OutputI
961944
if (!$this->signalRegistry) {
962945
throw new RuntimeException('Unable to subscribe to signal events. Make sure that the `pcntl` extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.');
963946
}
947+
948+
if ($this->dispatcher) {
949+
foreach ($this->signalsToDispatchEvent as $signal) {
950+
$event = new ConsoleSignalEvent($command, $input, $output, $signal);
951+
952+
$this->signalRegistry->register($signal, function ($signal, $hasNext) use ($event) {
953+
$this->dispatcher->dispatch($event, ConsoleEvents::SIGNAL);
954+
955+
// No more handlers, we try to simulate PHP default behavior
956+
if (!$hasNext) {
957+
if (!\in_array($signal, [\SIGUSR1, \SIGUSR2], true)) {
958+
exit(0);
959+
}
960+
}
961+
});
962+
}
963+
}
964+
964965
foreach ($command->getSubscribedSignals() as $signal) {
965966
$this->signalRegistry->register($signal, [$command, 'handleSignal']);
966967
}

Tests/ApplicationTest.php

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\Console\Application;
1616
use Symfony\Component\Console\Command\Command;
17+
use Symfony\Component\Console\Command\SignalableCommandInterface;
1718
use Symfony\Component\Console\CommandLoader\FactoryCommandLoader;
1819
use Symfony\Component\Console\DependencyInjection\AddConsoleCommandPass;
1920
use Symfony\Component\Console\Event\ConsoleCommandEvent;
@@ -1808,6 +1809,39 @@ public function testCommandNameMismatchWithCommandLoaderKeyThrows()
18081809
$app->setCommandLoader($loader);
18091810
$app->get('test');
18101811
}
1812+
1813+
/**
1814+
* @requires extension pcntl
1815+
*/
1816+
public function testSignal()
1817+
{
1818+
$command = new SignableCommand();
1819+
1820+
$dispatcherCalled = false;
1821+
$dispatcher = new EventDispatcher();
1822+
$dispatcher->addListener('console.signal', function () use (&$dispatcherCalled) {
1823+
$dispatcherCalled = true;
1824+
});
1825+
1826+
$application = new Application();
1827+
$application->setAutoExit(false);
1828+
$application->setDispatcher($dispatcher);
1829+
$application->setSignalsToDispatchEvent(SIGALRM);
1830+
$application->add($command);
1831+
1832+
$this->assertFalse($command->signaled);
1833+
$this->assertFalse($dispatcherCalled);
1834+
1835+
$this->assertSame(0, $application->run(new ArrayInput(['signal'])));
1836+
$this->assertFalse($command->signaled);
1837+
$this->assertFalse($dispatcherCalled);
1838+
1839+
$command->loop = 100000;
1840+
pcntl_alarm(1);
1841+
$this->assertSame(1, $application->run(new ArrayInput(['signal'])));
1842+
$this->assertTrue($command->signaled);
1843+
$this->assertTrue($dispatcherCalled);
1844+
}
18111845
}
18121846

18131847
class CustomApplication extends Application
@@ -1865,3 +1899,33 @@ public function isEnabled(): bool
18651899
return false;
18661900
}
18671901
}
1902+
1903+
class SignableCommand extends Command implements SignalableCommandInterface
1904+
{
1905+
public $signaled = false;
1906+
public $loop = 100;
1907+
1908+
protected static $defaultName = 'signal';
1909+
1910+
public function getSubscribedSignals(): array
1911+
{
1912+
return [SIGALRM];
1913+
}
1914+
1915+
public function handleSignal(int $signal): void
1916+
{
1917+
$this->signaled = true;
1918+
}
1919+
1920+
protected function execute(InputInterface $input, OutputInterface $output)
1921+
{
1922+
for ($i = 0; $i < $this->loop; ++$i) {
1923+
usleep(100);
1924+
if ($this->signaled) {
1925+
return 1;
1926+
}
1927+
}
1928+
1929+
return 0;
1930+
}
1931+
}

0 commit comments

Comments
 (0)