Skip to content

Commit

Permalink
Handle SIGINT gracefully
Browse files Browse the repository at this point in the history
  • Loading branch information
jigarius committed Dec 13, 2023
1 parent 072d349 commit e7df73c
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 4 deletions.
46 changes: 43 additions & 3 deletions src/Command/ExecCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Drall\Model\EnvironmentId;
use Drall\Model\Placeholder;
use Drall\Model\RawCommand;
use Drall\Trait\SignalAwareTrait;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
Expand All @@ -24,6 +25,8 @@
*/
class ExecCommand extends BaseCommand {

use SignalAwareTrait;

/**
* Maximum number of Drall workers.
*
Expand Down Expand Up @@ -163,11 +166,40 @@ protected function execute(InputInterface $input, OutputInterface $output): int
);
$exitCode = 0;

Loop::run(function () use ($values, $command, $placeholder, $output, $progressBar, $workers, &$exitCode) {
// Handle interruption signals to stop Drall gracefully.
$isStopping = FALSE;
$this->registerInterruptionListener(function () use (&$isStopping, $output) {
$output->writeln('');

// If a previous SIGINT was received, then stop immediately.
if ($isStopping) {
$this->logger->error('Interrupted by user.');
exit(1);
}

// Prepare to stop after the current item is processed.
$this->logger->warning('Stopping after current item.');
$isStopping = TRUE;
});

Loop::run(function () use (
$values,
$command,
$placeholder,
$output,
$progressBar,
$workers,
&$exitCode,
&$isStopping
) {
yield ConcurrentIterator\each(
Iterator\fromIterable($values),
new LocalSemaphore($workers),
function ($value) use ($command, $placeholder, $output, $progressBar, &$exitCode) {
function ($value) use ($command, $placeholder, $output, $progressBar, &$exitCode, &$isStopping) {
if ($isStopping) {
return;
}

$sCommand = Placeholder::replace([$placeholder->value => $value], $command);
$process = new Process("($sCommand) 2>&1", getcwd());

Expand All @@ -189,9 +221,17 @@ function ($value) use ($command, $placeholder, $output, $progressBar, &$exitCode
);
});

$progressBar->finish();
if (!$isStopping) {
$progressBar->finish();
}

$output->writeln('');

if ($isStopping) {
$this->logger->error('Interrupted by user.');
return 1;
}

return $exitCode;
}

Expand Down
17 changes: 17 additions & 0 deletions src/Trait/SignalAwareTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,21 @@ protected function registerSignalListener(int $signo, callable $handler): bool {
return TRUE;
}

/**
* Register a listener for SIGINT.
*
* @param callbale $handler
* A callable event listener.
*
* @return bool
* True if the listener was registered.
*/
protected function registerInterruptionListener(callable $handler): bool {
if (!defined('SIGINT')) {
return FALSE;
}

return self::registerSignalListener(SIGINT, $handler);
}

}
2 changes: 1 addition & 1 deletion src/Trait/SiteDetectorAwareTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public function setSiteDetector(SiteDetector $siteDetector) {
public function siteDetector(): SiteDetector {
if (!$this->hasSiteDetector()) {
throw new \BadMethodCallException(
'A site detecetor instance must first be assigned'
'A site detector instance must first be assigned'
);
}

Expand Down

0 comments on commit e7df73c

Please sign in to comment.