diff options
Diffstat (limited to 'lib/public/BackgroundJob')
-rw-r--r-- | lib/public/BackgroundJob/IJob.php | 50 | ||||
-rw-r--r-- | lib/public/BackgroundJob/IJobList.php | 139 | ||||
-rw-r--r-- | lib/public/BackgroundJob/IParallelAwareJob.php | 28 | ||||
-rw-r--r-- | lib/public/BackgroundJob/Job.php | 92 | ||||
-rw-r--r-- | lib/public/BackgroundJob/QueuedJob.php | 46 | ||||
-rw-r--r-- | lib/public/BackgroundJob/TimedJob.php | 68 |
6 files changed, 237 insertions, 186 deletions
diff --git a/lib/public/BackgroundJob/IJob.php b/lib/public/BackgroundJob/IJob.php index 3c2da42bf88..28a7df1c377 100644 --- a/lib/public/BackgroundJob/IJob.php +++ b/lib/public/BackgroundJob/IJob.php @@ -1,35 +1,19 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Daniel Kesselberg <mail@danielkesselberg.de> - * @author Joas Schilling <coding@schilljs.com> - * @author Lukas Reschke <lukas@statuscode.ch> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Robin Appelman <robin@icewind.nl> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * 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, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\BackgroundJob; use OCP\ILogger; /** - * Interface IJob + * This interface represents a background job run with cron + * + * To implement a background job, you must extend either \OCP\BackgroundJob\Job, + * \OCP\BackgroundJob\TimedJob or \OCP\BackgroundJob\QueuedJob * * @since 7.0.0 */ @@ -49,8 +33,24 @@ interface IJob { * @param IJobList $jobList The job list that manages the state of this job * @param ILogger|null $logger * @since 7.0.0 + * @deprecated 25.0.0 Use start() instead. This method will be removed + * with the ILogger interface + */ + public function execute(IJobList $jobList, ?ILogger $logger = null); + + /** + * Start the background job with the registered argument + * + * This methods will take care of running the background job, of initializing + * the state and cleaning up the job list after running the job. + * + * For common background job scenario, you will want to use TimedJob or QueuedJob + * instead of overwritting this method. + * + * @param IJobList $jobList The job list that manages the state of this job + * @since 25.0.0 */ - public function execute(IJobList $jobList, ILogger $logger = null); + public function start(IJobList $jobList): void; /** * @since 7.0.0 diff --git a/lib/public/BackgroundJob/IJobList.php b/lib/public/BackgroundJob/IJobList.php index eab37a03f36..c082ef22f2f 100644 --- a/lib/public/BackgroundJob/IJobList.php +++ b/lib/public/BackgroundJob/IJobList.php @@ -1,27 +1,9 @@ <?php + /** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Joas Schilling <coding@schilljs.com> - * @author Morris Jobke <hey@morrisjobke.de> - * @author Noveen Sachdeva <noveen.sachdeva@research.iiit.ac.in> - * @author Robin Appelman <robin@icewind.nl> - * @author Robin McCorkell <robin@mccorkell.me.uk> - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * 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, version 3, - * along with this program. If not, see <http://www.gnu.org/licenses/> - * + * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2016 ownCloud, Inc. + * SPDX-License-Identifier: AGPL-3.0-only */ namespace OCP\BackgroundJob; @@ -31,8 +13,8 @@ namespace OCP\BackgroundJob; * This interface provides functions to register background jobs * * To create a new background job create a new class that inherits from either - * \OC\BackgroundJob\Job, \OC\BackgroundJob\QueuedJob or - * \OC\BackgroundJob\TimedJob and register it using ->add($job, $argument), + * \OCP\BackgroundJob\Job, \OCP\BackgroundJob\QueuedJob or + * \OCP\BackgroundJob\TimedJob and register it using ->add($job, $argument), * $argument will be passed to the run() function of the job when the job is * executed. * @@ -41,66 +23,95 @@ namespace OCP\BackgroundJob; * be specified in the constructor of the job by calling * $this->setInterval($interval) with $interval in seconds. * + * This interface should be used directly and not implemented by an application. + * The implementation is provided by the server. + * * @since 7.0.0 */ interface IJobList { /** * Add a job to the list * - * @param \OCP\BackgroundJob\IJob|string $job - * @param mixed $argument The argument to be passed to $job->run() when the job is exectured + * @param IJob|class-string<IJob> $job + * @param mixed $argument The argument to be passed to $job->run() when the job is executed * @since 7.0.0 */ - public function add($job, $argument = null); + public function add($job, $argument = null): void; + + /** + * Add a job to the list but only run it after the given timestamp + * + * For cron background jobs this means the job will likely run shortly after the timestamp + * has been reached. For ajax background jobs the job might only run when users are active + * on the instance again. + * + * @param class-string<IJob> $job + * @param mixed $argument The serializable argument to be passed to $job->run() when the job is executed + * @since 28.0.0 + */ + public function scheduleAfter(string $job, int $runAfter, $argument = null): void; /** * Remove a job from the list * - * @param \OCP\BackgroundJob\IJob|string $job + * @param IJob|class-string<IJob> $job * @param mixed $argument * @since 7.0.0 */ - public function remove($job, $argument = null); + public function remove($job, $argument = null): void; + + /** + * Remove a job from the list by id + * + * @param int $id + * @since 30.0.0 + */ + public function removeById(int $id): void; /** * check if a job is in the list * - * @param \OCP\BackgroundJob\IJob|string $job + * @param IJob|class-string<IJob> $job * @param mixed $argument - * @return bool * @since 7.0.0 */ - public function has($job, $argument); + public function has($job, $argument): bool; /** - * get all jobs in the list + * Get jobs matching the search * - * @return \OCP\BackgroundJob\IJob[] - * @since 7.0.0 - * @deprecated 9.0.0 - This method is dangerous since it can cause load and - * memory problems when creating too many instances. + * @param IJob|class-string<IJob>|null $job + * @return array<IJob> + * @since 25.0.0 + * @deprecated 26.0.0 Use getJobsIterator instead to avoid duplicated job objects */ - public function getAll(); + public function getJobs($job, ?int $limit, int $offset): array; /** - * get the next job in the list + * Get jobs matching the search * - * @param bool $onlyTimeSensitive - * @return \OCP\BackgroundJob\IJob|null - * @since 7.0.0 - In 24.0.0 parameter $onlyTimeSensitive got added + * @param IJob|class-string<IJob>|null $job + * @return iterable<IJob> + * @since 26.0.0 */ - public function getNext(bool $onlyTimeSensitive = false): ?IJob; + public function getJobsIterator($job, ?int $limit, int $offset): iterable; + + /** + * Get the next job in the list + * + * @param bool $onlyTimeSensitive Whether we get only time sensitive jobs or not + * @param class-string<IJob>[]|null $jobClasses List of job classes to restrict which next job we get + * @return ?IJob the next job to run. Beware that this object may be a singleton and may be modified by the next call to buildJob. + * @since 7.0.0 - In 24.0.0 parameter $onlyTimeSensitive got added; In 30.0.0 parameter $jobClasses got added + */ + public function getNext(bool $onlyTimeSensitive = false, ?array $jobClasses = null): ?IJob; /** - * @param int $id - * @return \OCP\BackgroundJob\IJob|null * @since 7.0.0 */ - public function getById($id); + public function getById(int $id): ?IJob; /** - * @param int $id - * @return array|null * @since 23.0.0 */ public function getDetailsById(int $id): ?array; @@ -108,41 +119,53 @@ interface IJobList { /** * set the job that was last ran to the current time * - * @param \OCP\BackgroundJob\IJob $job * @since 7.0.0 */ - public function setLastJob(IJob $job); + public function setLastJob(IJob $job): void; /** * Remove the reservation for a job * - * @param IJob $job * @since 9.1.0 */ - public function unlockJob(IJob $job); + public function unlockJob(IJob $job): void; /** * set the lastRun of $job to now * - * @param IJob $job * @since 7.0.0 */ - public function setLastRun(IJob $job); + public function setLastRun(IJob $job): void; /** * set the run duration of $job * - * @param IJob $job - * @param $timeTaken * @since 12.0.0 */ - public function setExecutionTime(IJob $job, $timeTaken); + public function setExecutionTime(IJob $job, int $timeTaken): void; /** * Reset the $job so it executes on the next trigger * - * @param IJob $job * @since 23.0.0 */ public function resetBackgroundJob(IJob $job): void; + + /** + * Checks whether a job of the passed class was reserved to run + * in the last 6h + * + * @param string|null $className + * @return bool + * @since 27.0.0 + */ + public function hasReservedJob(?string $className): bool; + + /** + * Returns a count of jobs per Job class + * + * @return list<array{class:class-string, count:int}> + * @since 30.0.0 + */ + public function countByClass(): array; } diff --git a/lib/public/BackgroundJob/IParallelAwareJob.php b/lib/public/BackgroundJob/IParallelAwareJob.php new file mode 100644 index 00000000000..d69d897cb0c --- /dev/null +++ b/lib/public/BackgroundJob/IParallelAwareJob.php @@ -0,0 +1,28 @@ +<?php + +declare(strict_types=1); +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +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 5b20ac82684..2483387a9c9 100644 --- a/lib/public/BackgroundJob/Job.php +++ b/lib/public/BackgroundJob/Job.php @@ -1,33 +1,15 @@ <?php declare(strict_types=1); - /** - * @copyright Copyright (c) 2018, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @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/>. - * + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\BackgroundJob; use OCP\AppFramework\Utility\ITimeFactory; use OCP\ILogger; +use Psr\Log\LoggerInterface; /** * Base class for background jobs @@ -37,19 +19,12 @@ use OCP\ILogger; * * @since 15.0.0 */ -abstract class Job implements IJob { - - /** @var int $id */ - protected $id; - - /** @var int $lastRun */ - protected $lastRun; - - /** @var mixed $argument */ +abstract class Job implements IJob, IParallelAwareJob { + protected int $id = 0; + protected int $lastRun = 0; protected $argument; - - /** @var ITimeFactory */ - protected $time; + protected ITimeFactory $time; + protected bool $allowParallelRuns = true; /** * @since 15.0.0 @@ -61,31 +36,38 @@ abstract class Job implements IJob { /** * The function to prepare the execution of the job. * - * - * @param IJobList $jobList - * @param ILogger|null $logger + * @return void * * @since 15.0.0 + * @deprecated 25.0.0 Use start() instead. This method will be removed + * with the ILogger interface + */ + public function execute(IJobList $jobList, ?ILogger $logger = null) { + $this->start($jobList); + } + + /** + * @inheritdoc + * @since 25.0.0 */ - public function execute(IJobList $jobList, ILogger $logger = null) { + public function start(IJobList $jobList): void { $jobList->setLastRun($this); - if ($logger === null) { - $logger = \OC::$server->getLogger(); - } + $logger = \OCP\Server::get(LoggerInterface::class); try { + $jobDetails = get_class($this) . ' (id: ' . $this->getId() . ', arguments: ' . json_encode($this->getArgument()) . ')'; $jobStartTime = $this->time->getTime(); - $logger->debug('Run ' . get_class($this) . ' job with ID ' . $this->getId(), ['app' => 'cron']); + $logger->debug('Starting job ' . $jobDetails, ['app' => 'cron']); $this->run($this->argument); $timeTaken = $this->time->getTime() - $jobStartTime; - $logger->debug('Finished ' . get_class($this) . ' job with ID ' . $this->getId() . ' in ' . $timeTaken . ' seconds', ['app' => 'cron']); + $logger->debug('Finished job ' . $jobDetails . ' in ' . $timeTaken . ' seconds', ['app' => 'cron']); $jobList->setExecutionTime($this, $timeTaken); - } catch (\Exception $e) { + } catch (\Throwable $e) { if ($logger) { - $logger->logException($e, [ + $logger->error('Error while running background job ' . $jobDetails, [ 'app' => 'core', - 'message' => 'Error while running background job (class: ' . get_class($this) . ', arguments: ' . print_r($this->argument, true) . ')' + 'exception' => $e, ]); } } @@ -134,9 +116,29 @@ 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 + * @return void * * @since 15.0.0 */ diff --git a/lib/public/BackgroundJob/QueuedJob.php b/lib/public/BackgroundJob/QueuedJob.php index e7e6e9a2939..75e27d1d60f 100644 --- a/lib/public/BackgroundJob/QueuedJob.php +++ b/lib/public/BackgroundJob/QueuedJob.php @@ -1,27 +1,9 @@ <?php declare(strict_types=1); - /** - * @copyright Copyright (c) 2018, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @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/>. - * + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\BackgroundJob; @@ -33,17 +15,31 @@ use OCP\ILogger; * @since 15.0.0 */ abstract class QueuedJob extends Job { - /** - * run the job, then remove it from the joblist + * Run the job, then remove it from the joblist * * @param IJobList $jobList * @param ILogger|null $logger * * @since 15.0.0 + * @deprecated 25.0.0 Use start() instead. This method will be removed + * with the ILogger interface + */ + final public function execute($jobList, ?ILogger $logger = null) { + $this->start($jobList); + } + + /** + * Run the job, then remove it from the joblist + * + * @since 25.0.0 */ - final public function execute($jobList, ILogger $logger = null) { - $jobList->remove($this, $this->argument); - parent::execute($jobList, $logger); + final public function start(IJobList $jobList): void { + if ($this->id) { + $jobList->removeById($this->id); + } else { + $jobList->remove($this, $this->argument); + } + parent::start($jobList); } } diff --git a/lib/public/BackgroundJob/TimedJob.php b/lib/public/BackgroundJob/TimedJob.php index 579486f6fbf..486c03c5fda 100644 --- a/lib/public/BackgroundJob/TimedJob.php +++ b/lib/public/BackgroundJob/TimedJob.php @@ -1,33 +1,15 @@ <?php declare(strict_types=1); - /** - * @copyright Copyright (c) 2018, Roeland Jago Douma <roeland@famdouma.nl> - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Roeland Jago Douma <roeland@famdouma.nl> - * - * @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/>. - * + * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCP\BackgroundJob; -use OC\BackgroundJob\JobList; use OCP\ILogger; +use OCP\Server; +use Psr\Log\LoggerInterface; /** * Simple base class to extend to run periodic background jobs. @@ -36,13 +18,11 @@ use OCP\ILogger; * @since 15.0.0 */ abstract class TimedJob extends Job { - /** @var int */ - protected $interval = 0; - /** @var int */ - protected $timeSensitivity = IJob::TIME_SENSITIVE; + protected int $interval = 0; + protected int $timeSensitivity = IJob::TIME_SENSITIVE; /** - * set the interval for the job + * Set the interval for the job * * @param int $seconds the time to pass between two runs of the same job in seconds * @@ -53,6 +33,15 @@ abstract class TimedJob extends Job { } /** + * Get the interval [seconds] for the job + * + * @since 32.0.0 + */ + public function getInterval(): int { + return $this->interval; + } + + /** * Whether the background job is time sensitive and needs to run soon after * the scheduled interval, of if it is okay to be delayed until a later time. * @@ -74,8 +63,8 @@ abstract class TimedJob extends Job { * @since 24.0.0 */ public function setTimeSensitivity(int $sensitivity): void { - if ($sensitivity !== IJob::TIME_SENSITIVE && - $sensitivity !== IJob::TIME_INSENSITIVE) { + if ($sensitivity !== self::TIME_SENSITIVE + && $sensitivity !== self::TIME_INSENSITIVE) { throw new \InvalidArgumentException('Invalid sensitivity'); } @@ -83,16 +72,29 @@ abstract class TimedJob extends Job { } /** - * run the job if the last run is is more than the interval ago + * Run the job if the last run is more than the interval ago * - * @param JobList $jobList + * @param IJobList $jobList * @param ILogger|null $logger * * @since 15.0.0 + * @deprecated 25.0.0 Use start() instead + */ + final public function execute(IJobList $jobList, ?ILogger $logger = null) { + $this->start($jobList); + } + + /** + * Run the job if the last run is more than the interval ago + * + * @since 25.0.0 */ - final public function execute($jobList, ILogger $logger = null) { + final public function start(IJobList $jobList): void { if (($this->time->getTime() - $this->lastRun) > $this->interval) { - parent::execute($jobList, $logger); + if ($this->interval >= 12 * 60 * 60 && $this->isTimeSensitive()) { + Server::get(LoggerInterface::class)->debug('TimedJob ' . get_class($this) . ' has a configured interval of ' . $this->interval . ' seconds, but is also marked as time sensitive. Please consider marking it as time insensitive to allow more sensitive jobs to run when needed.'); + } + parent::start($jobList); } } } |