aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Wurst <ChristophWurst@users.noreply.github.com>2025-03-31 17:31:44 +0200
committerGitHub <noreply@github.com>2025-03-31 17:31:44 +0200
commite655ffeb435ad801ccceba361cf77d7893b9ee30 (patch)
tree1f1ec9a5fdc5d03f572fcfbccfc9771d5e76fd78
parent12e66badc44367bd7078faedf61f2b54be7c46b6 (diff)
parent2395526e6c25f1e8aafa1abf322a0d38c0ab5d54 (diff)
downloadnextcloud-server-e655ffeb435ad801ccceba361cf77d7893b9ee30.tar.gz
nextcloud-server-e655ffeb435ad801ccceba361cf77d7893b9ee30.zip
Merge pull request #50768 from nextcloud/perf/cron/delay-timedjob-checking
perf(cron): Delay (re)checking timed jobs
-rw-r--r--lib/private/BackgroundJob/JobList.php21
-rw-r--r--lib/public/BackgroundJob/TimedJob.php9
-rw-r--r--tests/lib/BackgroundJob/JobListTest.php29
-rw-r--r--tests/lib/BackgroundJob/TestTimedJobNew.php26
-rw-r--r--tests/lib/BackgroundJob/TimedJobTest.php14
5 files changed, 82 insertions, 17 deletions
diff --git a/lib/private/BackgroundJob/JobList.php b/lib/private/BackgroundJob/JobList.php
index 98d037e4dec..0d88200cff7 100644
--- a/lib/private/BackgroundJob/JobList.php
+++ b/lib/private/BackgroundJob/JobList.php
@@ -20,6 +20,7 @@ use OCP\IDBConnection;
use Psr\Log\LoggerInterface;
use function get_class;
use function json_encode;
+use function min;
use function strlen;
class JobList implements IJobList {
@@ -209,6 +210,26 @@ class JobList implements IJobList {
return $this->getNext($onlyTimeSensitive, $jobClasses);
}
+ if ($job instanceof \OCP\BackgroundJob\TimedJob) {
+ $now = $this->timeFactory->getTime();
+ $nextPossibleRun = $job->getLastRun() + $job->getInterval();
+ if ($now < $nextPossibleRun) {
+ // This job is not ready for execution yet. Set timestamps to the future to avoid
+ // re-checking with every cron run.
+ // To avoid bugs that lead to jobs never executing again, the future timestamp is
+ // capped at two days.
+ $nextCheck = min($nextPossibleRun, $now + 48 * 3600);
+ $updateTimedJob = $this->connection->getQueryBuilder();
+ $updateTimedJob->update('jobs')
+ ->set('last_checked', $updateTimedJob->createNamedParameter($nextCheck, IQueryBuilder::PARAM_INT))
+ ->where($updateTimedJob->expr()->eq('id', $updateTimedJob->createParameter('jobid')));
+ $updateTimedJob->setParameter('jobid', $row['id']);
+ $updateTimedJob->executeStatement();
+
+ return $this->getNext($onlyTimeSensitive, $jobClasses);
+ }
+ }
+
$update = $this->connection->getQueryBuilder();
$update->update('jobs')
->set('reserved_at', $update->createNamedParameter($this->timeFactory->getTime()))
diff --git a/lib/public/BackgroundJob/TimedJob.php b/lib/public/BackgroundJob/TimedJob.php
index 85ca34665b4..296bd9e4e32 100644
--- a/lib/public/BackgroundJob/TimedJob.php
+++ b/lib/public/BackgroundJob/TimedJob.php
@@ -33,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.
*
diff --git a/tests/lib/BackgroundJob/JobListTest.php b/tests/lib/BackgroundJob/JobListTest.php
index a9d7df0e6f4..bf21639d3aa 100644
--- a/tests/lib/BackgroundJob/JobListTest.php
+++ b/tests/lib/BackgroundJob/JobListTest.php
@@ -1,4 +1,7 @@
<?php
+
+declare(strict_types=1);
+
/**
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
@@ -153,7 +156,11 @@ class JobListTest extends TestCase {
$this->assertFalse($this->instance->has($job, 10));
}
- protected function createTempJob($class, $argument, $reservedTime = 0, $lastChecked = 0) {
+ protected function createTempJob($class,
+ $argument,
+ int $reservedTime = 0,
+ int $lastChecked = 0,
+ int $lastRun = 0): int {
if ($lastChecked === 0) {
$lastChecked = time();
}
@@ -163,11 +170,12 @@ class JobListTest extends TestCase {
->values([
'class' => $query->createNamedParameter($class),
'argument' => $query->createNamedParameter($argument),
- 'last_run' => $query->createNamedParameter(0, IQueryBuilder::PARAM_INT),
+ 'last_run' => $query->createNamedParameter($lastRun, IQueryBuilder::PARAM_INT),
'last_checked' => $query->createNamedParameter($lastChecked, IQueryBuilder::PARAM_INT),
'reserved_at' => $query->createNamedParameter($reservedTime, IQueryBuilder::PARAM_INT),
]);
- $query->execute();
+ $query->executeStatement();
+ return $query->getLastInsertId();
}
public function testGetNext(): void {
@@ -200,6 +208,21 @@ class JobListTest extends TestCase {
$this->assertEquals(2, $nextJob->getArgument());
}
+ public function testGetNextSkipTimed(): void {
+ $job = new TestTimedJobNew($this->timeFactory);
+ $jobId = $this->createTempJob(get_class($job), 1, 123456789, 12345, 123456789 - 5);
+ $this->timeFactory->expects(self::atLeastOnce())
+ ->method('getTime')
+ ->willReturn(123456789);
+
+ $nextJob = $this->instance->getNext();
+
+ self::assertNull($nextJob);
+ $job = $this->instance->getById($jobId);
+ self::assertInstanceOf(TestTimedJobNew::class, $job);
+ self::assertEquals(123456789 - 5, $job->getLastRun());
+ }
+
public function testGetNextSkipNonExisting(): void {
$job = new TestJob();
$this->createTempJob('\OC\Non\Existing\Class', 1, 0, 12345);
diff --git a/tests/lib/BackgroundJob/TestTimedJobNew.php b/tests/lib/BackgroundJob/TestTimedJobNew.php
new file mode 100644
index 00000000000..a40c4033655
--- /dev/null
+++ b/tests/lib/BackgroundJob/TestTimedJobNew.php
@@ -0,0 +1,26 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+namespace Test\BackgroundJob;
+
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\BackgroundJob\TimedJob;
+
+class TestTimedJobNew extends TimedJob {
+ public bool $ran = false;
+
+ public function __construct(ITimeFactory $timeFactory) {
+ parent::__construct($timeFactory);
+ $this->setInterval(10);
+ }
+
+ public function run($argument) {
+ $this->ran = true;
+ }
+}
diff --git a/tests/lib/BackgroundJob/TimedJobTest.php b/tests/lib/BackgroundJob/TimedJobTest.php
index ad0f54ebe4a..6037365104f 100644
--- a/tests/lib/BackgroundJob/TimedJobTest.php
+++ b/tests/lib/BackgroundJob/TimedJobTest.php
@@ -8,20 +8,6 @@
namespace Test\BackgroundJob;
use OCP\AppFramework\Utility\ITimeFactory;
-use OCP\BackgroundJob\TimedJob;
-
-class TestTimedJobNew extends TimedJob {
- public bool $ran = false;
-
- public function __construct(ITimeFactory $timeFactory) {
- parent::__construct($timeFactory);
- $this->setInterval(10);
- }
-
- public function run($argument) {
- $this->ran = true;
- }
-}
class TimedJobTest extends \Test\TestCase {
private DummyJobList $jobList;