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)) { $executionData = $lasts[$job->getKey()]->getLastExecutionData(); $this->entityManager ->createQuery(self::UPDATE_BEFORE_EXEC) ->setParameters([ 'now' => new \DateTimeImmutable('now'), 'key' => $job->getKey(), ]) ->execute(); } else { $execution = new CronJobExecution($job->getKey()); $this->entityManager->persist($execution); $this->entityManager->flush(); $executionData = $execution->getLastExecutionData(); } $this->entityManager->clear(); // note: at this step, the entity manager does not have any entity CronJobExecution // into his internal memory try { $this->logger->info(sprintf('%sWill run job', self::LOG_PREFIX), ['job' => $job->getKey()]); $result = $job->run($executionData); $this->entityManager ->createQuery(self::UPDATE_AFTER_EXEC) ->setParameters([ 'now' => new \DateTimeImmutable('now'), 'status' => CronJobExecution::SUCCESS, 'key' => $job->getKey(), ]) ->execute(); if (null !== $result) { $this->entityManager ->createQuery(self::UPDATE_LAST_EXECUTION_DATA) ->setParameter('data', $result, Types::JSON) ->setParameter('key', $job->getKey(), Types::STRING) ->execute(); } $this->logger->info(sprintf('%sSuccessfully run job', self::LOG_PREFIX), ['job' => $job->getKey()]); return; } catch (\Exception) { $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: array, 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) { if ($job->getKey() === $forceJob) { $job->run([]); } } } }