bug #38845 [Console] Register signal handling only for commands implemeting SignalableCommandInterface (lyrixx)
This PR was merged into the 5.x branch.
Discussion
----------
[Console] Register signal handling only for commands implemeting SignalableCommandInterface
| Q | A
| ------------- | ---
| Branch? | 5.x for features
| Bug fix? | yes
| New feature? | no
| Deprecations? | no
| Tickets | Fix #38820
| License | MIT
| Doc PR |
---
Actually, it does not make sens to listen all signals for all commands.
This commit also add more tests for this part of code.
Commits
-------
37b1faec8c
[Console] Register signal handling only for commands implemeting SignalableCommandInterface
This commit is contained in:
commit
268b5b746c
@ -286,23 +286,6 @@ class Application implements ResetInterface
|
||||
$command = $this->find($alternative);
|
||||
}
|
||||
|
||||
if ($this->dispatcher && $this->signalRegistry) {
|
||||
foreach ($this->signalsToDispatchEvent as $signal) {
|
||||
$event = new ConsoleSignalEvent($command, $input, $output, $signal);
|
||||
|
||||
$this->signalRegistry->register($signal, function ($signal, $hasNext) use ($event) {
|
||||
$this->dispatcher->dispatch($event, ConsoleEvents::SIGNAL);
|
||||
|
||||
// No more handlers, we try to simulate PHP default behavior
|
||||
if (!$hasNext) {
|
||||
if (!\in_array($signal, [\SIGUSR1, \SIGUSR2], true)) {
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$this->runningCommand = $command;
|
||||
$exitCode = $this->doRunCommand($command, $input, $output);
|
||||
$this->runningCommand = null;
|
||||
@ -961,6 +944,24 @@ class Application implements ResetInterface
|
||||
if (!$this->signalRegistry) {
|
||||
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.');
|
||||
}
|
||||
|
||||
if ($this->dispatcher) {
|
||||
foreach ($this->signalsToDispatchEvent as $signal) {
|
||||
$event = new ConsoleSignalEvent($command, $input, $output, $signal);
|
||||
|
||||
$this->signalRegistry->register($signal, function ($signal, $hasNext) use ($event) {
|
||||
$this->dispatcher->dispatch($event, ConsoleEvents::SIGNAL);
|
||||
|
||||
// No more handlers, we try to simulate PHP default behavior
|
||||
if (!$hasNext) {
|
||||
if (!\in_array($signal, [\SIGUSR1, \SIGUSR2], true)) {
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($command->getSubscribedSignals() as $signal) {
|
||||
$this->signalRegistry->register($signal, [$command, 'handleSignal']);
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ namespace Symfony\Component\Console\Tests;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Command\SignalableCommandInterface;
|
||||
use Symfony\Component\Console\CommandLoader\FactoryCommandLoader;
|
||||
use Symfony\Component\Console\DependencyInjection\AddConsoleCommandPass;
|
||||
use Symfony\Component\Console\Event\ConsoleCommandEvent;
|
||||
@ -1808,6 +1809,39 @@ class ApplicationTest extends TestCase
|
||||
$app->setCommandLoader($loader);
|
||||
$app->get('test');
|
||||
}
|
||||
|
||||
/**
|
||||
* @requires extension pcntl
|
||||
*/
|
||||
public function testSignal()
|
||||
{
|
||||
$command = new SignableCommand();
|
||||
|
||||
$dispatcherCalled = false;
|
||||
$dispatcher = new EventDispatcher();
|
||||
$dispatcher->addListener('console.signal', function () use (&$dispatcherCalled) {
|
||||
$dispatcherCalled = true;
|
||||
});
|
||||
|
||||
$application = new Application();
|
||||
$application->setAutoExit(false);
|
||||
$application->setDispatcher($dispatcher);
|
||||
$application->setSignalsToDispatchEvent(SIGALRM);
|
||||
$application->add($command);
|
||||
|
||||
$this->assertFalse($command->signaled);
|
||||
$this->assertFalse($dispatcherCalled);
|
||||
|
||||
$this->assertSame(0, $application->run(new ArrayInput(['signal'])));
|
||||
$this->assertFalse($command->signaled);
|
||||
$this->assertFalse($dispatcherCalled);
|
||||
|
||||
$command->loop = 100000;
|
||||
pcntl_alarm(1);
|
||||
$this->assertSame(1, $application->run(new ArrayInput(['signal'])));
|
||||
$this->assertTrue($command->signaled);
|
||||
$this->assertTrue($dispatcherCalled);
|
||||
}
|
||||
}
|
||||
|
||||
class CustomApplication extends Application
|
||||
@ -1865,3 +1899,33 @@ class DisabledCommand extends Command
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class SignableCommand extends Command implements SignalableCommandInterface
|
||||
{
|
||||
public $signaled = false;
|
||||
public $loop = 100;
|
||||
|
||||
protected static $defaultName = 'signal';
|
||||
|
||||
public function getSubscribedSignals(): array
|
||||
{
|
||||
return [SIGALRM];
|
||||
}
|
||||
|
||||
public function handleSignal(int $signal): void
|
||||
{
|
||||
$this->signaled = true;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
for ($i = 0; $i < $this->loop; ++$i) {
|
||||
usleep(100);
|
||||
if ($this->signaled) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user