aboutsummaryrefslogtreecommitdiffstats
path: root/lib/public/BackgroundJob
diff options
context:
space:
mode:
Diffstat (limited to 'lib/public/BackgroundJob')
-rw-r--r--lib/public/BackgroundJob/IJob.php50
-rw-r--r--lib/public/BackgroundJob/IJobList.php139
-rw-r--r--lib/public/BackgroundJob/IParallelAwareJob.php28
-rw-r--r--lib/public/BackgroundJob/Job.php92
-rw-r--r--lib/public/BackgroundJob/QueuedJob.php46
-rw-r--r--lib/public/BackgroundJob/TimedJob.php68
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);
}
}
}