Skip to content

Commit 14759a9

Browse files
committed
Duplicate class to fix support for Symfony 7.3
1 parent 2f4e269 commit 14759a9

1 file changed

Lines changed: 176 additions & 65 deletions

File tree

src/AbstractTerminableCommand.php

Lines changed: 176 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -5,104 +5,215 @@
55
namespace Facile\TerminableLoop;
66

77
use Symfony\Component\Console\Command\Command;
8+
use Symfony\Component\Console\Command\SignalableCommandInterface;
89
use Symfony\Component\Console\Input\InputInterface;
910
use Symfony\Component\Console\Output\OutputInterface;
1011

11-
abstract class AbstractTerminableCommand extends Command
12-
{
13-
private const REQUEST_TO_TERMINATE = 143;
12+
if (
13+
PHP_VERSION_ID >= 80_200
14+
&& interface_exists(SignalableCommandInterface::class)
15+
&& in_array(
16+
SignalableCommandInterface::class,
17+
class_implements(Command::class),
18+
true
19+
)
20+
) {
21+
abstract class AbstractTerminableCommand extends Command implements SignalableCommandInterface
22+
{
23+
private const REQUEST_TO_TERMINATE = 143;
1424

15-
/** @var int */
16-
private $sleepDuration;
25+
/** @var int */
26+
private $sleepDuration;
1727

18-
/** @var bool */
19-
private $signalShutdownRequested;
28+
/** @var bool */
29+
private $signalShutdownRequested;
2030

21-
public function __construct(?string $name = null)
22-
{
23-
$this->sleepDuration = 0;
24-
$this->signalShutdownRequested = false;
31+
public function __construct(?string $name = null)
32+
{
33+
$this->sleepDuration = 0;
34+
$this->signalShutdownRequested = false;
2535

26-
parent::__construct($name);
27-
}
36+
parent::__construct($name);
37+
}
2838

29-
final protected function execute(InputInterface $input, OutputInterface $output): int
30-
{
31-
$this->trapSignals();
39+
final protected function execute(InputInterface $input, OutputInterface $output): int
40+
{
41+
$output->writeln('Starting ' . ($this->getName() ?? static::class), OutputInterface::VERBOSITY_VERBOSE);
42+
43+
if ($this->signalShutdownRequested) {
44+
$output->writeln('Signal received, skipping execution', OutputInterface::VERBOSITY_NORMAL);
3245

33-
$output->writeln('Starting ' . ($this->getName() ?? static::class), OutputInterface::VERBOSITY_VERBOSE);
46+
return self::REQUEST_TO_TERMINATE;
47+
}
3448

35-
if ($this->signalShutdownRequested) {
36-
$output->writeln('Signal received, skipping execution', OutputInterface::VERBOSITY_NORMAL);
49+
$exitCode = $this->commandBody($input, $output);
3750

38-
return self::REQUEST_TO_TERMINATE;
51+
$this->sleep($output);
52+
53+
/** @psalm-suppress DocblockTypeContradiction */
54+
if ($this->signalShutdownRequested) {
55+
$output->writeln('Signal received, terminating with exit code ' . self::REQUEST_TO_TERMINATE, OutputInterface::VERBOSITY_NORMAL);
56+
57+
return self::REQUEST_TO_TERMINATE;
58+
}
59+
60+
return $exitCode;
3961
}
4062

41-
$exitCode = $this->commandBody($input, $output);
63+
abstract protected function commandBody(InputInterface $input, OutputInterface $output): int;
4264

43-
$this->sleep($output);
65+
public function handleSignal(int $signal, int|false $previousExitCode = 0): int|false
66+
{
67+
switch ($signal) {
68+
// Shutdown signals
69+
case SIGTERM:
70+
case SIGINT:
71+
$this->signalShutdownRequested = true;
72+
}
4473

45-
/** @psalm-suppress DocblockTypeContradiction */
46-
if ($this->signalShutdownRequested) {
47-
$output->writeln('Signal received, terminating with exit code ' . self::REQUEST_TO_TERMINATE, OutputInterface::VERBOSITY_NORMAL);
74+
return false;
75+
}
4876

49-
return self::REQUEST_TO_TERMINATE;
77+
/**
78+
* @return list<int>
79+
*/
80+
public function getSubscribedSignals(): array
81+
{
82+
return [
83+
SIGTERM,
84+
SIGINT,
85+
];
5086
}
5187

52-
return $exitCode;
53-
}
88+
protected function getSleepDuration(): int
89+
{
90+
return $this->sleepDuration;
91+
}
5492

55-
abstract protected function commandBody(InputInterface $input, OutputInterface $output): int;
93+
protected function setSleepDuration(int $sleepDuration): void
94+
{
95+
if ($sleepDuration < 0) {
96+
throw new \InvalidArgumentException('Invalid timeout provided to ' . __METHOD__);
97+
}
5698

57-
public function handleSignal(int $signal): void
58-
{
59-
switch ($signal) {
60-
// Shutdown signals
61-
case SIGTERM:
62-
case SIGINT:
63-
$this->signalShutdownRequested = true;
64-
break;
99+
$this->sleepDuration = $sleepDuration;
65100
}
66-
}
67101

68-
private function trapSignals(): void
69-
{
70-
pcntl_async_signals(true);
102+
private function sleep(OutputInterface $output): void
103+
{
104+
if (0 === $this->sleepDuration) {
105+
return;
106+
}
71107

72-
// Add the signal handler
73-
pcntl_signal(SIGTERM, [$this, 'handleSignal']);
74-
pcntl_signal(SIGINT, [$this, 'handleSignal']);
75-
}
108+
$sleepCountDown = $this->sleepDuration;
76109

77-
protected function getSleepDuration(): int
78-
{
79-
return $this->sleepDuration;
80-
}
110+
while (! $this->signalShutdownRequested && --$sleepCountDown) {
111+
sleep(1);
112+
}
81113

82-
protected function setSleepDuration(int $sleepDuration): void
114+
$output->writeln(
115+
sprintf('Slept %d second(s)', $this->sleepDuration - $sleepCountDown),
116+
OutputInterface::VERBOSITY_DEBUG
117+
);
118+
}
119+
}
120+
} else {
121+
abstract class AbstractTerminableCommand extends Command
83122
{
84-
if ($sleepDuration < 0) {
85-
throw new \InvalidArgumentException('Invalid timeout provided to ' . __METHOD__);
123+
private const REQUEST_TO_TERMINATE = 143;
124+
125+
/** @var int */
126+
private $sleepDuration;
127+
128+
/** @var bool */
129+
private $signalShutdownRequested;
130+
131+
public function __construct(?string $name = null)
132+
{
133+
$this->sleepDuration = 0;
134+
$this->signalShutdownRequested = false;
135+
136+
parent::__construct($name);
86137
}
87138

88-
$this->sleepDuration = $sleepDuration;
89-
}
139+
final protected function execute(InputInterface $input, OutputInterface $output): int
140+
{
141+
$this->trapSignals();
90142

91-
private function sleep(OutputInterface $output): void
92-
{
93-
if (0 === $this->sleepDuration) {
94-
return;
143+
$output->writeln('Starting ' . ($this->getName() ?? static::class), OutputInterface::VERBOSITY_VERBOSE);
144+
145+
if ($this->signalShutdownRequested) {
146+
$output->writeln('Signal received, skipping execution', OutputInterface::VERBOSITY_NORMAL);
147+
148+
return self::REQUEST_TO_TERMINATE;
149+
}
150+
151+
$exitCode = $this->commandBody($input, $output);
152+
153+
$this->sleep($output);
154+
155+
/** @psalm-suppress DocblockTypeContradiction */
156+
if ($this->signalShutdownRequested) {
157+
$output->writeln('Signal received, terminating with exit code ' . self::REQUEST_TO_TERMINATE, OutputInterface::VERBOSITY_NORMAL);
158+
159+
return self::REQUEST_TO_TERMINATE;
160+
}
161+
162+
return $exitCode;
95163
}
96164

97-
$sleepCountDown = $this->sleepDuration;
165+
abstract protected function commandBody(InputInterface $input, OutputInterface $output): int;
166+
167+
public function handleSignal(int $signal): void
168+
{
169+
switch ($signal) {
170+
// Shutdown signals
171+
case SIGTERM:
172+
case SIGINT:
173+
$this->signalShutdownRequested = true;
174+
break;
175+
}
176+
}
177+
178+
private function trapSignals(): void
179+
{
180+
pcntl_async_signals(true);
181+
182+
// Add the signal handler
183+
pcntl_signal(SIGTERM, [$this, 'handleSignal']);
184+
pcntl_signal(SIGINT, [$this, 'handleSignal']);
185+
}
98186

99-
while (! $this->signalShutdownRequested && --$sleepCountDown) {
100-
sleep(1);
187+
protected function getSleepDuration(): int
188+
{
189+
return $this->sleepDuration;
101190
}
102191

103-
$output->writeln(
104-
sprintf('Slept %d second(s)', $this->sleepDuration - $sleepCountDown),
105-
OutputInterface::VERBOSITY_DEBUG
106-
);
192+
protected function setSleepDuration(int $sleepDuration): void
193+
{
194+
if ($sleepDuration < 0) {
195+
throw new \InvalidArgumentException('Invalid timeout provided to ' . __METHOD__);
196+
}
197+
198+
$this->sleepDuration = $sleepDuration;
199+
}
200+
201+
private function sleep(OutputInterface $output): void
202+
{
203+
if (0 === $this->sleepDuration) {
204+
return;
205+
}
206+
207+
$sleepCountDown = $this->sleepDuration;
208+
209+
while (! $this->signalShutdownRequested && --$sleepCountDown) {
210+
sleep(1);
211+
}
212+
213+
$output->writeln(
214+
sprintf('Slept %d second(s)', $this->sleepDuration - $sleepCountDown),
215+
OutputInterface::VERBOSITY_DEBUG
216+
);
217+
}
107218
}
108219
}

0 commit comments

Comments
 (0)