diff options
author | Côme Chilliet <91878298+come-nc@users.noreply.github.com> | 2023-04-25 12:10:43 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-25 12:10:43 +0200 |
commit | 7250f54ca32c1c353470fbc4042ee648e57b760f (patch) | |
tree | 15be4b1e070978f81ee9481238e27f5d704e6997 /lib/public | |
parent | 77bb867ad5c74216364d593c419419412d27594f (diff) | |
parent | 06d6cf4ebcc49d97f89b46e127599b97f8fa1800 (diff) | |
download | nextcloud-server-7250f54ca32c1c353470fbc4042ee648e57b760f.tar.gz nextcloud-server-7250f54ca32c1c353470fbc4042ee648e57b760f.zip |
Merge pull request #37835 from nextcloud/feat/background-allow-parallel-runs
feat(BackgroundJobs): Allow preventing parallel runs for a job class
Diffstat (limited to 'lib/public')
-rw-r--r-- | lib/public/BackgroundJob/IJobList.php | 9 | ||||
-rw-r--r-- | lib/public/BackgroundJob/IParallelAwareJob.php | 47 | ||||
-rw-r--r-- | lib/public/BackgroundJob/Job.php | 33 |
3 files changed, 86 insertions, 3 deletions
diff --git a/lib/public/BackgroundJob/IJobList.php b/lib/public/BackgroundJob/IJobList.php index e8d0380e604..71faefb8825 100644 --- a/lib/public/BackgroundJob/IJobList.php +++ b/lib/public/BackgroundJob/IJobList.php @@ -145,4 +145,13 @@ interface IJobList { * @since 23.0.0 */ public function resetBackgroundJob(IJob $job): void; + + /** + * Checks whether a job of the passed class is reserved to run + * + * @param string|null $className + * @return bool + * @since 27.0.0 + */ + public function hasReservedJob(?string $className): bool; } diff --git a/lib/public/BackgroundJob/IParallelAwareJob.php b/lib/public/BackgroundJob/IParallelAwareJob.php new file mode 100644 index 00000000000..30c69e16b5f --- /dev/null +++ b/lib/public/BackgroundJob/IParallelAwareJob.php @@ -0,0 +1,47 @@ +<?php + +declare(strict_types=1); + + +/** + * @copyright Copyright (c) 2023, Marcel Klehr <mklehr@gmx.net> + * + * @author Marcel Klehr <mklehr@gmx.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OCP\BackgroundJob; + +/** + * @since 27.0.0 + */ +interface IParallelAwareJob { + /** + * Set this to false to prevent two Jobs from the same class from running in parallel + * + * @param bool $allow + * @return void + * @since 27.0.0 + */ + public function setAllowParallelRuns(bool $allow): void; + + /** + * @return bool + * @since 27.0.0 + */ + public function getAllowParallelRuns(): bool; +} diff --git a/lib/public/BackgroundJob/Job.php b/lib/public/BackgroundJob/Job.php index d60fb5905c9..455fb3d42e7 100644 --- a/lib/public/BackgroundJob/Job.php +++ b/lib/public/BackgroundJob/Job.php @@ -38,11 +38,13 @@ use Psr\Log\LoggerInterface; * * @since 15.0.0 */ -abstract class Job implements IJob { +abstract class Job implements IJob, IParallelAwareJob { protected int $id = 0; protected int $lastRun = 0; protected $argument; protected ITimeFactory $time; + protected bool $allowParallelRuns = true; + private ?ILogger $logger = null; /** * @since 15.0.0 @@ -61,6 +63,7 @@ abstract class Job implements IJob { * @since 15.0.0 */ public function execute(IJobList $jobList, ILogger $logger = null) { + $this->logger = $logger; $this->start($jobList); } @@ -70,7 +73,12 @@ abstract class Job implements IJob { */ public function start(IJobList $jobList): void { $jobList->setLastRun($this); - $logger = \OCP\Server::get(LoggerInterface::class); + $logger = $this->logger ?? \OCP\Server::get(LoggerInterface::class); + + if (!$this->getAllowParallelRuns() && $jobList->hasReservedJob(get_class($this))) { + $logger->debug('Skipping ' . get_class($this) . ' job with ID ' . $this->getId() . ' because another job with the same class is already running', ['app' => 'cron']); + return; + } try { $jobStartTime = $this->time->getTime(); @@ -80,7 +88,7 @@ abstract class Job implements IJob { $logger->debug('Finished ' . get_class($this) . ' job with ID ' . $this->getId() . ' in ' . $timeTaken . ' seconds', ['app' => 'cron']); $jobList->setExecutionTime($this, $timeTaken); - } catch (\Exception $e) { + } catch (\Throwable $e) { if ($logger) { $logger->error('Error while running background job (class: ' . get_class($this) . ', arguments: ' . print_r($this->argument, true) . ')', [ 'app' => 'core', @@ -133,6 +141,25 @@ abstract class Job implements IJob { } /** + * Set this to false to prevent two Jobs from this class from running in parallel + * + * @param bool $allow + * @return void + * @since 27.0.0 + */ + public function setAllowParallelRuns(bool $allow): void { + $this->allowParallelRuns = $allow; + } + + /** + * @return bool + * @since 27.0.0 + */ + public function getAllowParallelRuns(): bool { + return $this->allowParallelRuns; + } + + /** * The actual function that is called to run the job * * @param $argument |