Last active
August 8, 2019 06:39
-
-
Save grachevko/80ad1f51ebd4e4dce6b7c76ca163dc2c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
namespace App\Command; | |
use App\Symfony\EventDispatcher; | |
use Doctrine\DBAL\Driver\Connection; | |
use Symfony\Component\Console\Command\Command; | |
use Symfony\Component\Console\ConsoleEvents; | |
use Symfony\Component\Console\Event\ConsoleErrorEvent; | |
use Symfony\Component\Console\Input\InputInterface; | |
use Symfony\Component\Console\Input\InputOption; | |
use Symfony\Component\Console\Output\OutputInterface; | |
use Symfony\Component\Console\Style\SymfonyStyle; | |
/** | |
* @author Konstantin Grachev <[email protected]> | |
*/ | |
abstract class LoopedCommand extends Command | |
{ | |
use EventDispatcher; | |
/** | |
* @var \DateInterval | |
*/ | |
private $interval; | |
/** | |
* @var bool | |
*/ | |
private $terminate = false; | |
/** | |
* @var SymfonyStyle | |
*/ | |
private $io; | |
/** | |
* @var Connection|\Doctrine\DBAL\Connection | |
*/ | |
private $conn; | |
/** | |
* @required | |
*/ | |
public function setConnection(Connection $conn): void | |
{ | |
$this->conn = $conn; | |
} | |
abstract protected function loop(InputInterface $input, OutputInterface $output); | |
protected function configure(): void | |
{ | |
$this->addOption('loop-interval', null, InputOption::VALUE_OPTIONAL, 'Interval between run, null to disable'); | |
} | |
protected function initialize(InputInterface $input, OutputInterface $output): void | |
{ | |
parent::initialize($input, $output); | |
if ($interval = $input->getOption('loop-interval')) { | |
$this->interval = \DateInterval::createFromDateString($interval); | |
} | |
$this->io = new class(new SymfonyStyle($input, $output), (bool) $interval) { | |
/** @var SymfonyStyle */ | |
private $io; | |
/** @var bool */ | |
private $isLoop; | |
public function __construct(SymfonyStyle $io, bool $isLoop) | |
{ | |
$this->io = $io; | |
$this->isLoop = $isLoop; | |
} | |
public function __call($name, $arguments) | |
{ | |
if (!$this->isLoop) { | |
return; | |
} | |
return call_user_func_array([$this->io, $name], $arguments); | |
} | |
}; | |
pcntl_signal(SIGHUP, function (): void { | |
$this->io->warning('SIGHUP signal was received'); | |
$this->terminate = true; | |
}); | |
pcntl_signal(SIGINT, function (): void { | |
exit; | |
}); | |
} | |
protected function execute(InputInterface $input, OutputInterface $output): void | |
{ | |
if ($this->interval) { | |
$this->io->success(sprintf( | |
'Loop with "%s" interval has begun', | |
$this->interval->format('%d days %h hours %i minutes and %s seconds') | |
)); | |
} | |
$databaseWaitTimeout = (int) $this->conn->executeQuery('SELECT @@wait_timeout')->fetchColumn(); | |
$index = 0; | |
while (true) { | |
pcntl_signal_dispatch(); | |
if ($this->terminate) { | |
break; | |
} | |
if (false === $this->conn->ping()) { | |
$this->conn->close(); | |
$this->conn->connect(); | |
} | |
$this->io->write(sprintf('[ %s ] Loop index "%s"', (new \DateTime())->format('Y-m-d H:i:s'), ++$index)); | |
try { | |
$this->loop($input, $output); | |
$this->io->writeln(sprintf(' [ %s ]', (new \DateTime())->format('Y-m-d H:i:s'))); | |
} catch (\Exception $e) { | |
$this->getApplication()->renderException($e, $output); | |
$this->dispatcher->dispatch(ConsoleEvents::ERROR, new ConsoleErrorEvent($input, $output, $e, $this)); | |
} | |
if (!$this->interval) { | |
break; | |
} | |
$now = new \DateTimeImmutable(); | |
$seconds = $now->add($this->interval)->getTimestamp() - $now->getTimestamp(); | |
if ($seconds > $databaseWaitTimeout) { | |
$this->conn->close(); | |
} | |
sleep($seconds); | |
} | |
$this->io->success('Loop successful finished'); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment