diff options
author | Christoph Wurst <ChristophWurst@users.noreply.github.com> | 2025-03-31 17:31:44 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-03-31 17:31:44 +0200 |
commit | e655ffeb435ad801ccceba361cf77d7893b9ee30 (patch) | |
tree | 1f1ec9a5fdc5d03f572fcfbccfc9771d5e76fd78 | |
parent | 12e66badc44367bd7078faedf61f2b54be7c46b6 (diff) | |
parent | 2395526e6c25f1e8aafa1abf322a0d38c0ab5d54 (diff) | |
download | nextcloud-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.php | 21 | ||||
-rw-r--r-- | lib/public/BackgroundJob/TimedJob.php | 9 | ||||
-rw-r--r-- | tests/lib/BackgroundJob/JobListTest.php | 29 | ||||
-rw-r--r-- | tests/lib/BackgroundJob/TestTimedJobNew.php | 26 | ||||
-rw-r--r-- | tests/lib/BackgroundJob/TimedJobTest.php | 14 |
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; |