Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 41ca1df

Browse files
authored
Ability to shutdown in startup without running the loop & Symfony 7 support (#57)
Also added a lot of types & updated dependencies.
1 parent d5cc743 commit 41ca1df

File tree

8 files changed

+73
-125
lines changed

8 files changed

+73
-125
lines changed

.travis.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,8 @@ cache:
55
- $HOME/.composer/cache/files
66

77
php:
8-
- 7.2
9-
- 7.3
10-
- 7.4
11-
- 8.0
8+
- 8.2
9+
- 8.3
1210

1311
before_script:
1412
- COMPOSER_ROOT_VERSION=dev-master composer --prefer-dist install

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ Use composer to include it into your Symfony project:
1414

1515
### What version to use?
1616
Symfony did make some breaking changes, so you should make sure to use a compatible bundle version:
17-
* Version 4.0.* for Symfony 6 and higher
17+
* Version 5.* for Symfony 7 and higher
18+
* Version 4.* for Symfony 6
1819
* Version 3.0.* for Symfony 4 and 5
1920
* Version 2.0.* for Symfony 3
2021
* Version 1.3.* for Symfony 2.8+

UPGRADE.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Upgrades
2+
3+
Important information about breaking changes and backward incompabilities
4+
5+
## 4.* to 5.0
6+
7+
### `EndlessContainerAwareCommand` removed
8+
9+
Since `ContainerAwareInterface` has been deprecated in Symfony 6.4, programmers are encouraged to use dependency injection instead in the constructor.
10+
11+
Therefore, it makes no sense to keep `EndlessContainerAwareCommand`. If you need to call `EntityManager::clear()` on your doctrine instance inside `EndlessCommand::finishIteration()`, you have to handle this in your code now.
12+
13+
If you need to access any service, inject it in the constructor of your derived class.

composer.json

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@
1515
"issues": "https://github.com/mac-cain13/daemonizable-command/issues"
1616
},
1717
"require": {
18-
"php": ">=8.0",
19-
"symfony/console": "^6.0 || ^7.0",
20-
"symfony/dependency-injection": "^6.0 || ^7.0"
21-
},
18+
"php": ">=8.2",
19+
"symfony/console": "^7.0",
20+
"symfony/dependency-injection": "^7.0"
21+
},
2222
"require-dev": {
23-
"phpunit/phpunit": "^8.0 || ^9.0"
24-
},
23+
"phpunit/phpunit": "^9.0",
24+
"ext-pcntl": "*",
25+
"ext-posix": "*"
26+
},
2527
"suggest": {
2628
"symfony/filesystem": "If you can't use Upstart or systemd"
2729
},

examples/ExampleCommand.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
namespace Acme\DemoBundle\Command;
44

5-
use Wrep\Daemonizable\Command\EndlessContainerAwareCommand;
5+
use Wrep\Daemonizable\Command\EndlessCommand;
66
use Symfony\Component\Console\Output\OutputInterface;
77
use Symfony\Component\Console\Input\InputInterface;
88

9-
class ExampleCommand extends EndlessContainerAwareCommand
9+
class ExampleCommand extends EndlessCommand
1010
{
1111
// This is just a normal Command::configure() method
1212
protected function configure()
@@ -38,7 +38,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
3838

3939
if ( false === file_put_contents('/tmp/acme-avg-score.txt', $score) )
4040
{
41-
// Set the returncode tot non-zero if there are any errors
41+
// Set the return code to non-zero if there are any errors
4242
$this->setReturnCode(1);
4343

4444
// After this execute method returns we want the command exit

src/Wrep/Daemonizable/Command/EndlessCommand.php

Lines changed: 42 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44

55
namespace Wrep\Daemonizable\Command;
66

7+
use Exception;
8+
use InvalidArgumentException;
79
use Symfony\Component\Console\Exception\LogicException;
10+
use Throwable;
811
use Wrep\Daemonizable\Exception\ShutdownEndlessCommandException;
912
use Symfony\Component\Console\Command\Command;
1013
use Symfony\Component\Console\Output\OutputInterface;
11-
use Symfony\Component\Console\Output\NullOutput;
1214
use Symfony\Component\Console\Input\InputInterface;
1315
use Symfony\Component\Console\Input\InputOption;
1416
use function pcntl_async_signals;
@@ -18,12 +20,12 @@ abstract class EndlessCommand extends Command
1820
{
1921
public const DEFAULT_TIMEOUT = 5;
2022

21-
private $code;
22-
private $timeout;
23-
private $returnCode;
24-
private $shutdownRequested;
25-
private $lastUsage;
26-
private $lastPeakUsage;
23+
/** @var int<0,max> $timeout */
24+
private int $timeout;
25+
private int $returnCode;
26+
private bool $shutdownRequested;
27+
private int $lastUsage;
28+
private int $lastPeakUsage;
2729

2830
/**
2931
* @see Command::__construct()
@@ -59,7 +61,7 @@ public function run(InputInterface $input, OutputInterface $output): int
5961
// Enable async signals for fast signal processing
6062
try {
6163
pcntl_async_signals(true);
62-
} catch (\Throwable $e) {
64+
} catch (Throwable $e) {
6365
declare(ticks=1);
6466
}
6567

@@ -93,16 +95,16 @@ public function handleSignal(int $signal): void
9395
* @param InputInterface $input An InputInterface instance
9496
* @param OutputInterface $output An OutputInterface instance
9597
*
96-
* @return integer The command exit code
98+
* @return int The command exit code
9799
*
98-
* @throws \Exception
100+
* @throws Exception
99101
*/
100-
protected function runloop(InputInterface $input, OutputInterface $output)
102+
protected function runloop(InputInterface $input, OutputInterface $output): int
101103
{
102104
try {
103105
$this->starting($input, $output);
104106

105-
do {
107+
while (! $this->shutdownRequested) {
106108
// Start iteration
107109
$this->startIteration($input, $output);
108110

@@ -113,12 +115,12 @@ protected function runloop(InputInterface $input, OutputInterface $output)
113115
$this->finishIteration($input, $output);
114116

115117
// Request shutdown if we only should run once
116-
if ((bool)$input->getOption('run-once')) {
118+
if ($input->getOption('run-once')) {
117119
$this->shutdown();
118120
}
119121

120122
// Print memory report if requested
121-
if ((bool)$input->getOption('detect-leaks')) {
123+
if ($input->getOption('detect-leaks')) {
122124
// Gather memory info
123125
$peak = $this->getMemoryInfo(true);
124126
$curr = $this->getMemoryInfo(false);
@@ -139,8 +141,9 @@ protected function runloop(InputInterface $input, OutputInterface $output)
139141
if (! $this->shutdownRequested) {
140142
usleep($this->timeout);
141143
}
142-
} while (! $this->shutdownRequested);
144+
}
143145
} catch (ShutdownEndlessCommandException $ignore) {
146+
// this exception is just caught to break out of the loop and signal we are done and finalize
144147
}
145148

146149
// Prepare for shutdown
@@ -179,13 +182,14 @@ protected function finishIteration(InputInterface $input, OutputInterface $outpu
179182
/**
180183
* Get information about the current memory usage
181184
*
182-
* @param bool True for peak usage, false for current usage
185+
* @param bool $peak True for peak usage, false for current usage
183186
*
184-
* @return array
187+
* @return array{amount: int, diff: int, diffPercentage: int|float, statusDescription: 'decreasing'|'increasing'|'stable', statusType: 'comment'|'error'|'info'}
185188
*/
186189
private function getMemoryInfo(bool $peak = false): array
187190
{
188191
$lastUsage = ($peak) ? $this->lastPeakUsage : $this->lastUsage;
192+
$info = [];
189193
$info['amount'] = ($peak) ? memory_get_peak_usage() : memory_get_usage();
190194
$info['diff'] = $info['amount'] - $lastUsage;
191195
$info['diffPercentage'] = ($lastUsage == 0) ? 0 : $info['diff'] / ($lastUsage / 100);
@@ -212,22 +216,6 @@ private function getMemoryInfo(bool $peak = false): array
212216
return $info;
213217
}
214218

215-
/**
216-
* @see Command::setCode()
217-
*/
218-
public function setCode(callable $code): static
219-
{
220-
// Exact copy of our parent
221-
// Makes sure we can access to call it every iteration
222-
if (! is_callable($code)) {
223-
throw new \InvalidArgumentException('Invalid callable provided to Command::setCode.');
224-
}
225-
226-
$this->code = $code;
227-
228-
return $this;
229-
}
230-
231219
/**
232220
* Execution logic.
233221
*
@@ -252,19 +240,20 @@ protected function execute(InputInterface $input, OutputInterface $output): int
252240
/**
253241
* Set the timeout of this command.
254242
*
255-
* @param int|float $timeout Timeout between two iterations in seconds
256-
*
257-
* @return Command The current instance
243+
* @param float $timeout Timeout between two iterations in seconds
258244
*
259-
* @throws \InvalidArgumentException
245+
* @throws InvalidArgumentException
260246
*/
261-
public function setTimeout(float $timeout)
247+
public function setTimeout(float $timeout): self
262248
{
263249
if ($timeout < 0) {
264-
throw new \InvalidArgumentException('Invalid timeout provided to Command::setTimeout.');
250+
throw new InvalidArgumentException('Invalid timeout provided to Command::setTimeout.');
265251
}
266252

267-
$this->timeout = (int) (1000000 * $timeout);
253+
/** @var int<0,max> $timeout */
254+
$timeout = (int)(1000000 * $timeout);
255+
256+
$this->timeout = $timeout;
268257

269258
return $this;
270259
}
@@ -282,16 +271,14 @@ public function getTimeout(): float
282271
/**
283272
* Set the return code of this command.
284273
*
285-
* @param int 0 if everything went fine, or an error code
286-
*
287-
* @return Command The current instance
274+
* @param int $returnCode 0 if everything went fine, or an error code
288275
*
289-
* @throws \InvalidArgumentException
276+
* @throws InvalidArgumentException
290277
*/
291-
public function setReturnCode(int $returnCode)
278+
public function setReturnCode(int $returnCode): self
292279
{
293280
if ($returnCode < 0) {
294-
throw new \InvalidArgumentException('Invalid returnCode provided to Command::setReturnCode.');
281+
throw new InvalidArgumentException('Invalid returnCode provided to Command::setReturnCode.');
295282
}
296283

297284
$this->returnCode = $returnCode;
@@ -313,11 +300,10 @@ public function getReturnCode(): int
313300
* Instruct the command to end the endless loop gracefully.
314301
*
315302
* This will finish the current iteration and give the command a chance
316-
* to cleanup.
303+
* to clean up.
317304
*
318-
* @return Command The current instance
319305
*/
320-
public function shutdown()
306+
public function shutdown(): self
321307
{
322308
$this->shutdownRequested = true;
323309

@@ -331,19 +317,17 @@ public function shutdown()
331317
* execution code takes quite long to finish on a point where you still can exit
332318
* without corrupting any data.
333319
*
334-
* @return Command The current instance
335-
*
336320
* @throws ShutdownEndlessCommandException
337321
*/
338-
protected function throwExceptionOnShutdown()
322+
protected function throwExceptionOnShutdown(): self
339323
{
340324
// Make sure all signals are handled
341325
if (function_exists('pcntl_signal_dispatch')) {
342326
pcntl_signal_dispatch();
343327
}
344328

345329
if ($this->shutdownRequested) {
346-
throw new ShutdownEndlessCommandException('Volunteered to break out of the EndlessCommand runloop because a shutdown is requested.');
330+
throw new ShutdownEndlessCommandException('Volunteered to break out of the EndlessCommand::runloop because a shutdown is requested.');
347331
}
348332

349333
return $this;
@@ -362,4 +346,9 @@ protected function throwExceptionOnShutdown()
362346
protected function finalize(InputInterface $input, OutputInterface $output): void
363347
{
364348
}
349+
350+
protected function isShutdownRequested(): bool
351+
{
352+
return $this->shutdownRequested;
353+
}
365354
}

src/Wrep/Daemonizable/Command/EndlessContainerAwareCommand.php

Lines changed: 0 additions & 57 deletions
This file was deleted.

src/Wrep/Daemonizable/Exception/ShutdownEndlessCommandException.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace Wrep\Daemonizable\Exception;
66

7-
class ShutdownEndlessCommandException extends \RuntimeException
7+
use RuntimeException;
8+
9+
class ShutdownEndlessCommandException extends RuntimeException
810
{
911
}

0 commit comments

Comments
 (0)