I need to execute Symfony command quite frequently (like every 5-10 seconds) but my runtime environement restricts the lowest time possible of cron trigger to 1 minute. So, I've come up with a pretty nasty solution, looks like this. I've had created AbstractRepetitiveCommand
class, which I then extended, providing implemenation of workToExecute
method.
abstract class AbstractRepetitiveCommand extends Command
{
protected int $overallMinutes = 1;
protected int $timesPerMinute = 60;
protected function execute(InputInterface $input, OutputInterface $output)
{
$startTime = microtime(true);
while (microtime(true) < $startTime + 60 * $this->overallMinutes - 60 / $this->timesPerMinute) {
if (isset($last) && microtime(true) < $last + 60 / $this->timesPerMinute) {
continue;
}
$last = microtime(true);
$this->workToExecute($input, $output);
}
}
protected function workToExecute(InputInterface $input, OutputInterface $output)
{
return;
}
}
class DoChecksCommand extends AbstractRepetitiveCommand
{
protected int $overallMinutes = 5;
protected int $timePerMinute = 4;
protected static $defaultName = 'checks:do';
/**
* @var InvestmentCheckerService
*/
private InvestmentCheckerService $checkerService;
/**
* @var EntityManagerInterface
*/
private EntityManagerInterface $entityManager;
public function __construct(InvestmentCheckerService $checkerService, EntityManagerInterface $entityManager)
{
parent::__construct('DoChecks');
$this->checkerService = $checkerService;
$this->entityManager = $entityManager;
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @throws \Exception
*/
protected function workToExecute(InputInterface $input, OutputInterface $output)
{
/** @var ArrayCollection | Pair[] $pairs */
$pairs = $this->entityManager->getRepository(Pair::class)->findAll();
foreach ($pairs as $pair) {
$this->checkerService->processChecks($pair);
$this->entityManager->persist($pair);
$this->entityManager->flush();
}
}
}
There are two problems with this approach:
- When 2 o this kind of commands run simultanously, they don't recognize each other's changes made by flush. Is there a way to refresh connection, so with every run the data is fetched from database?
- This solution is really ugly overall. I'm probably overthinking/overcomplicating it, so please advise whether you see any better approach to the goal I want to achieve.
For now I've tried to use clear()
method of EntityManager
at the start of every loop but it didn't change anything.
I thought about closing the connection, but then I don't see any easy way to reconnect again after closing.
Thank you for any help.