diff --git a/wcfsetup/install/files/lib/system/background/BackgroundQueueHandler.class.php b/wcfsetup/install/files/lib/system/background/BackgroundQueueHandler.class.php index d08e9e7cc53..c9ee141718b 100644 --- a/wcfsetup/install/files/lib/system/background/BackgroundQueueHandler.class.php +++ b/wcfsetup/install/files/lib/system/background/BackgroundQueueHandler.class.php @@ -5,6 +5,7 @@ use wcf\data\user\User; use wcf\system\background\job\AbstractBackgroundJob; use wcf\system\background\job\AbstractUniqueBackgroundJob; +use wcf\system\database\util\PreparedStatementConditionBuilder; use wcf\system\exception\ParentClassException; use wcf\system\session\SessionHandler; use wcf\system\SingletonFactory; @@ -72,49 +73,59 @@ public function enqueueAt(AbstractBackgroundJob|array $jobs, int $time): void $jobs = [$jobs]; } + $identifiers = []; foreach ($jobs as $job) { if (!($job instanceof AbstractBackgroundJob)) { throw new ParentClassException(\get_class($job), AbstractBackgroundJob::class); } + + if ($job instanceof AbstractUniqueBackgroundJob) { + $identifiers[] = $job->identifier(); + } } - $committed = false; - try { - WCF::getDB()->beginTransaction(); - $sql = "INSERT INTO wcf1_background_job - (job, time,identifier) - VALUES (?, ?, ?)"; + if ($identifiers !== []) { + $conditions = new PreparedStatementConditionBuilder(); + $conditions->add("identifier IN (?)", [$identifiers]); + + $sql = "SELECT DISTINCT identifier + FROM wcf1_background_job + {$conditions}"; $statement = WCF::getDB()->prepare($sql); - $sql = "SELECT jobID - FROM wcf1_background_job - WHERE identifier = ? - FOR UPDATE"; - $selectJobStatement = WCF::getDB()->prepare($sql); - - foreach ($jobs as $job) { - $identifier = null; - if ($job instanceof AbstractUniqueBackgroundJob) { - // Check if the job is already in the queue - $selectJobStatement->execute([$job->identifier()]); - $jobID = $selectJobStatement->fetchSingleColumn(); - if ($jobID !== false) { - continue; + $statement->execute($conditions->getParameters()); + $existingJobs = $statement->fetchAll(\PDO::FETCH_COLUMN); + + $jobs = \array_filter( + $jobs, + function ($job) use ($existingJobs) { + if ($job instanceof AbstractUniqueBackgroundJob && \in_array($job->identifier(), $existingJobs)) { + return false; } - $identifier = $job->identifier(); + + return true; } + ); - $statement->execute([ - \serialize($job), - $time, - $identifier - ]); + if ($jobs === []) { + return; } - WCF::getDB()->commitTransaction(); - $committed = true; - } finally { - if (!$committed) { - WCF::getDB()->rollBackTransaction(); + } + + $sql = "INSERT INTO wcf1_background_job + (job, time, identifier) + VALUES (?, ?, ?)"; + $statement = WCF::getDB()->prepare($sql); + foreach ($jobs as $job) { + $identifier = null; + if ($job instanceof AbstractUniqueBackgroundJob) { + $identifier = $job->identifier(); } + + $statement->execute([ + \serialize($job), + $time, + $identifier, + ]); } }