*/ private iterable $jobs; private LoggerInterface $logger; /** * @param CronJobInterface[] $jobs */ public function __construct( CronJobExecutionRepositoryInterface $cronJobExecutionRepository, EntityManagerInterface $entityManager, iterable $jobs, LoggerInterface $logger ) { $this->cronJobExecutionRepository = $cronJobExecutionRepository; $this->entityManager = $entityManager; $this->jobs = $jobs; $this->logger = $logger; } public function run(?string $forceJob = null): void { if (null !== $forceJob) { $this->runForce($forceJob); return; } [$orderedJobs, $lasts] = $this->getOrderedJobs(); foreach ($orderedJobs as $job) { if ($job->canRun($lasts[$job->getKey()] ?? null)) { if (array_key_exists($job->getKey(), $lasts)) { $this->entityManager ->createQuery(self::UPDATE_BEFORE_EXEC) ->setParameters([ 'now' => new DateTimeImmutable('now'), 'key' => $job->getKey(), ]); } else { $execution = new CronJobExecution($job->getKey()); $this->entityManager->persist($execution); $this->entityManager->flush(); } $this->entityManager->clear(); try { $this->logger->info(sprintf('%sWill run job', self::LOG_PREFIX), ['job' => $job->getKey()]); $job->run(); $this->entityManager ->createQuery(self::UPDATE_AFTER_EXEC) ->setParameters([ 'now' => new DateTimeImmutable('now'), 'status' => CronJobExecution::SUCCESS, 'key' => $job->getKey(), ]) ->execute(); $this->logger->info(sprintf('%sSuccessfully run job', self::LOG_PREFIX), ['job' => $job->getKey()]); return; } catch (Exception $e) { $this->logger->error(sprintf('%sRunning job failed', self::LOG_PREFIX), ['job' => $job->getKey()]); $this->entityManager ->createQuery(self::UPDATE_AFTER_EXEC) ->setParameters([ 'now' => new DateTimeImmutable('now'), 'status' => CronJobExecution::FAILURE, 'key' => $job->getKey(), ]) ->execute(); return; } } } } /** * @return array<0: CronJobInterface[], 1: array> */ private function getOrderedJobs(): array { /** @var array $lasts */ $lasts = []; foreach ($this->cronJobExecutionRepository->findAll() as $execution) { $lasts[$execution->getKey()] = $execution; } // order by last, NULL first $orderedJobs = iterator_to_array($this->jobs); usort( $orderedJobs, static function (CronJobInterface $a, CronJobInterface $b) use ($lasts): int { if ( (!array_key_exists($a->getKey(), $lasts) && !array_key_exists($b->getKey(), $lasts)) ) { return 0; } if (!array_key_exists($a->getKey(), $lasts) && array_key_exists($b->getKey(), $lasts)) { return -1; } if (!array_key_exists($b->getKey(), $lasts) && array_key_exists($a->getKey(), $lasts)) { return 1; } return $lasts[$a->getKey()]->getLastStart() <=> $lasts[$b->getKey()]->getLastStart(); } ); return [$orderedJobs, $lasts]; } private function runForce(string $forceJob): void { foreach ($this->jobs as $job) { $job->run(); } } }