diff --git a/lib/private/BackgroundJob/JobList.php b/lib/private/BackgroundJob/JobList.php index ddacba67fcc2f..b1fe620ecb333 100644 --- a/lib/private/BackgroundJob/JobList.php +++ b/lib/private/BackgroundJob/JobList.php @@ -23,6 +23,9 @@ use function strlen; class JobList implements IJobList { + /** @var array */ + protected array $alreadyVisitedParallelBlocked = []; + public function __construct( protected IDBConnection $connection, protected IConfig $config, @@ -197,6 +200,12 @@ public function getNext(bool $onlyTimeSensitive = false, ?array $jobClasses = nu $job = $this->buildJob($row); if ($job instanceof IParallelAwareJob && !$job->getAllowParallelRuns() && $this->hasReservedJob(get_class($job))) { + if (!isset($this->alreadyVisitedParallelBlocked[get_class($job)])) { + $this->alreadyVisitedParallelBlocked[get_class($job)] = $job->getId(); + } elseif ($this->alreadyVisitedParallelBlocked[get_class($job)] === $job->getId()) { + $this->logger->info('Skipped through all jobs and revisited a IParallelAwareJob blocked job again, giving up.', ['app' => 'cron']); + return null; + } $this->logger->info('Skipping ' . get_class($job) . ' job with ID ' . $job->getId() . ' because another job with the same class is already running', ['app' => 'cron']); $update = $this->connection->getQueryBuilder(); @@ -209,6 +218,10 @@ public function getNext(bool $onlyTimeSensitive = false, ?array $jobClasses = nu return $this->getNext($onlyTimeSensitive, $jobClasses); } + if ($job !== null && isset($this->alreadyVisitedParallelBlocked[get_class($job)])) { + unset($this->alreadyVisitedParallelBlocked[get_class($job)]); + } + $update = $this->connection->getQueryBuilder(); $update->update('jobs') ->set('reserved_at', $update->createNamedParameter($this->timeFactory->getTime()))