Skip to content

Commit 0e686fc

Browse files
committed
feat: Port jobs table to snowflakes ids
Signed-off-by: Carl Schwan <[email protected]>
1 parent 31af870 commit 0e686fc

File tree

13 files changed

+147
-178
lines changed

13 files changed

+147
-178
lines changed

apps/dav/tests/unit/BackgroundJob/RefreshWebcalJobTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ protected function setUp(): void {
4545
#[\PHPUnit\Framework\Attributes\DataProvider('runDataProvider')]
4646
public function testRun(int $lastRun, int $time, bool $process): void {
4747
$backgroundJob = new RefreshWebcalJob($this->refreshWebcalService, $this->config, $this->logger, $this->timeFactory);
48-
$backgroundJob->setId(42);
48+
$backgroundJob->setId('42');
4949

5050
$backgroundJob->setArgument([
5151
'principaluri' => 'principals/users/testuser',

core/Command/Background/Delete.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ protected function configure(): void {
3535
}
3636

3737
protected function execute(InputInterface $input, OutputInterface $output): int {
38-
$jobId = (int)$input->getArgument('job-id');
38+
$jobId = (string)$input->getArgument('job-id');
3939

4040
$job = $this->jobList->getById($jobId);
4141
if ($job === null) {

core/Command/Background/Job.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ protected function configure(): void {
4444
}
4545

4646
protected function execute(InputInterface $input, OutputInterface $output): int {
47-
$jobId = (int)$input->getArgument('job-id');
47+
$jobId = (string)$input->getArgument('job-id');
4848

4949
$job = $this->jobList->getById($jobId);
5050
if ($job === null) {
@@ -87,7 +87,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
8787
return 0;
8888
}
8989

90-
protected function printJobInfo(int $jobId, IJob $job, OutputInterface $output): void {
90+
protected function printJobInfo(string $jobId, IJob $job, OutputInterface $output): void {
9191
$row = $this->jobList->getDetailsById($jobId);
9292

9393
$lastRun = new \DateTime();

core/Command/Background/JobBase.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public function __construct(
2727
parent::__construct();
2828
}
2929

30-
protected function printJobInfo(int $jobId, IJob $job, OutputInterface $output): void {
30+
protected function printJobInfo(string $jobId, IJob $job, OutputInterface $output): void {
3131
$row = $this->jobList->getDetailsById($jobId);
3232

3333
if ($row === null) {
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
namespace OC\Core\Migrations;
10+
11+
use Closure;
12+
use OCP\DB\ISchemaWrapper;
13+
use OCP\Migration\Attributes\ModifyColumn;
14+
use OCP\Migration\IOutput;
15+
use OCP\Migration\SimpleMigrationStep;
16+
use Override;
17+
18+
#[ModifyColumn(table: 'jobs', name: 'id', description: 'Remove auto-increment')]
19+
class Version33000Date20251124110529 extends SimpleMigrationStep {
20+
/**
21+
* @param Closure(): ISchemaWrapper $schemaClosure The `\Closure` returns a `ISchemaWrapper`
22+
*/
23+
#[Override]
24+
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
25+
$schema = $schemaClosure();
26+
27+
if ($schema->hasTable('jobs')) {
28+
$schema->dropAutoincrementColumn('jobs', 'id');
29+
}
30+
31+
return $schema;
32+
}
33+
}

lib/composer/composer/autoload_classmap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1537,6 +1537,7 @@
15371537
'OC\\Core\\Migrations\\Version33000Date20251023110529' => $baseDir . '/core/Migrations/Version33000Date20251023110529.php',
15381538
'OC\\Core\\Migrations\\Version33000Date20251023120529' => $baseDir . '/core/Migrations/Version33000Date20251023120529.php',
15391539
'OC\\Core\\Migrations\\Version33000Date20251106131209' => $baseDir . '/core/Migrations/Version33000Date20251106131209.php',
1540+
'OC\\Core\\Migrations\\Version33000Date20251124110529' => $baseDir . '/core/Migrations/Version33000Date20251124110529.php',
15401541
'OC\\Core\\Migrations\\Version33000Date20251126152410' => $baseDir . '/core/Migrations/Version33000Date20251126152410.php',
15411542
'OC\\Core\\Notification\\CoreNotifier' => $baseDir . '/core/Notification/CoreNotifier.php',
15421543
'OC\\Core\\ResponseDefinitions' => $baseDir . '/core/ResponseDefinitions.php',

lib/composer/composer/autoload_static.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1578,6 +1578,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
15781578
'OC\\Core\\Migrations\\Version33000Date20251023110529' => __DIR__ . '/../../..' . '/core/Migrations/Version33000Date20251023110529.php',
15791579
'OC\\Core\\Migrations\\Version33000Date20251023120529' => __DIR__ . '/../../..' . '/core/Migrations/Version33000Date20251023120529.php',
15801580
'OC\\Core\\Migrations\\Version33000Date20251106131209' => __DIR__ . '/../../..' . '/core/Migrations/Version33000Date20251106131209.php',
1581+
'OC\\Core\\Migrations\\Version33000Date20251124110529' => __DIR__ . '/../../..' . '/core/Migrations/Version33000Date20251124110529.php',
15811582
'OC\\Core\\Migrations\\Version33000Date20251126152410' => __DIR__ . '/../../..' . '/core/Migrations/Version33000Date20251126152410.php',
15821583
'OC\\Core\\Notification\\CoreNotifier' => __DIR__ . '/../../..' . '/core/Notification/CoreNotifier.php',
15831584
'OC\\Core\\ResponseDefinitions' => __DIR__ . '/../../..' . '/core/ResponseDefinitions.php',

lib/private/BackgroundJob/JobList.php

Lines changed: 38 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
*/
88
namespace OC\BackgroundJob;
99

10-
use OCP\AppFramework\QueryException;
1110
use OCP\AppFramework\Utility\ITimeFactory;
1211
use OCP\AutoloadNotAllowedException;
1312
use OCP\BackgroundJob\IJob;
@@ -17,25 +16,30 @@
1716
use OCP\DB\QueryBuilder\IQueryBuilder;
1817
use OCP\IConfig;
1918
use OCP\IDBConnection;
19+
use OCP\Snowflake\IGenerator;
20+
use Override;
21+
use Psr\Container\ContainerExceptionInterface;
2022
use Psr\Log\LoggerInterface;
2123
use function get_class;
2224
use function json_encode;
2325
use function min;
2426
use function strlen;
2527

2628
class JobList implements IJobList {
27-
/** @var array<string, int> */
29+
/** @var array<string, string> */
2830
protected array $alreadyVisitedParallelBlocked = [];
2931

3032
public function __construct(
31-
protected IDBConnection $connection,
32-
protected IConfig $config,
33-
protected ITimeFactory $timeFactory,
34-
protected LoggerInterface $logger,
33+
protected readonly IDBConnection $connection,
34+
protected readonly IConfig $config,
35+
protected readonly ITimeFactory $timeFactory,
36+
protected readonly LoggerInterface $logger,
37+
protected readonly IGenerator $generator,
3538
) {
3639
}
3740

38-
public function add($job, $argument = null, ?int $firstCheck = null): void {
41+
#[Override]
42+
public function add(IJob|string $job, mixed $argument = null, ?int $firstCheck = null): void {
3943
if ($firstCheck === null) {
4044
$firstCheck = $this->timeFactory->getTime();
4145
}
@@ -51,6 +55,7 @@ public function add($job, $argument = null, ?int $firstCheck = null): void {
5155
if (!$this->has($job, $argument)) {
5256
$query->insert('jobs')
5357
->values([
58+
'id' => $query->createNamedParameter($this->generator->nextId(), IQueryBuilder::PARAM_INT),
5459
'class' => $query->createNamedParameter($class),
5560
'argument' => $query->createNamedParameter($argumentJson),
5661
'argument_hash' => $query->createNamedParameter(hash('sha256', $argumentJson)),
@@ -68,15 +73,12 @@ public function add($job, $argument = null, ?int $firstCheck = null): void {
6873
$query->executeStatement();
6974
}
7075

71-
public function scheduleAfter(string $job, int $runAfter, $argument = null): void {
76+
public function scheduleAfter(string $job, int $runAfter, mixed $argument = null): void {
7277
$this->add($job, $argument, $runAfter);
7378
}
7479

75-
/**
76-
* @param IJob|string $job
77-
* @param mixed $argument
78-
*/
79-
public function remove($job, $argument = null): void {
80+
#[Override]
81+
public function remove(IJob|string $job, mixed $argument = null): void {
8082
$class = ($job instanceof IJob) ? get_class($job) : $job;
8183

8284
$query = $this->connection->getQueryBuilder();
@@ -104,20 +106,16 @@ public function remove($job, $argument = null): void {
104106
}
105107
}
106108

107-
public function removeById(int $id): void {
109+
#[Override]
110+
public function removeById(string $id): void {
108111
$query = $this->connection->getQueryBuilder();
109112
$query->delete('jobs')
110113
->where($query->expr()->eq('id', $query->createNamedParameter($id, IQueryBuilder::PARAM_INT)));
111114
$query->executeStatement();
112115
}
113116

114-
/**
115-
* check if a job is in the list
116-
*
117-
* @param IJob|class-string<IJob> $job
118-
* @param mixed $argument
119-
*/
120-
public function has($job, $argument): bool {
117+
#[Override]
118+
public function has(IJob|string $job, mixed $argument): bool {
121119
$class = ($job instanceof IJob) ? get_class($job) : $job;
122120
$argument = json_encode($argument);
123121

@@ -135,18 +133,16 @@ public function has($job, $argument): bool {
135133
return (bool)$row;
136134
}
137135

138-
public function getJobs($job, ?int $limit, int $offset): array {
136+
#[Override]
137+
public function getJobs(IJob|string|null $job, ?int $limit, int $offset): array {
139138
$iterable = $this->getJobsIterator($job, $limit, $offset);
140139
return (is_array($iterable))
141140
? $iterable
142141
: iterator_to_array($iterable);
143142
}
144143

145-
/**
146-
* @param IJob|class-string<IJob>|null $job
147-
* @return iterable<IJob> Avoid to store these objects as they may share a Singleton instance. You should instead use these IJobs instances while looping on the iterable.
148-
*/
149-
public function getJobsIterator($job, ?int $limit, int $offset): iterable {
144+
#[Override]
145+
public function getJobsIterator(IJob|string|null $job, ?int $limit, int $offset): iterable {
150146
$query = $this->connection->getQueryBuilder();
151147
$query->select('*')
152148
->from('jobs')
@@ -169,9 +165,7 @@ public function getJobsIterator($job, ?int $limit, int $offset): iterable {
169165
$result->closeCursor();
170166
}
171167

172-
/**
173-
* @inheritDoc
174-
*/
168+
#[Override]
175169
public function getNext(bool $onlyTimeSensitive = false, ?array $jobClasses = null): ?IJob {
176170
$query = $this->connection->getQueryBuilder();
177171
$query->select('*')
@@ -279,10 +273,8 @@ public function getNext(bool $onlyTimeSensitive = false, ?array $jobClasses = nu
279273
}
280274
}
281275

282-
/**
283-
* @return ?IJob The job matching the id. Beware that this object may be a singleton and may be modified by the next call to buildJob.
284-
*/
285-
public function getById(int $id): ?IJob {
276+
#[Override]
277+
public function getById(string $id): ?IJob {
286278
$row = $this->getDetailsById($id);
287279

288280
if ($row) {
@@ -292,7 +284,8 @@ public function getById(int $id): ?IJob {
292284
return null;
293285
}
294286

295-
public function getDetailsById(int $id): ?array {
287+
#[Override]
288+
public function getDetailsById(string $id): ?array {
296289
$query = $this->connection->getQueryBuilder();
297290
$query->select('*')
298291
->from('jobs')
@@ -320,7 +313,7 @@ private function buildJob(array $row): ?IJob {
320313
// Try to load the job as a service
321314
/** @var IJob $job */
322315
$job = \OCP\Server::get($row['class']);
323-
} catch (QueryException $e) {
316+
} catch (ContainerExceptionInterface $e) {
324317
if (class_exists($row['class'])) {
325318
$class = $row['class'];
326319
$job = new $class();
@@ -336,7 +329,7 @@ private function buildJob(array $row): ?IJob {
336329
// This most likely means an invalid job was enqueued. We can ignore it.
337330
return null;
338331
}
339-
$job->setId((int)$row['id']);
332+
$job->setId($row['id']);
340333
$job->setLastRun((int)$row['last_run']);
341334
$job->setArgument(json_decode($row['argument'], true));
342335
return $job;
@@ -351,12 +344,10 @@ private function buildJob(array $row): ?IJob {
351344
*/
352345
public function setLastJob(IJob $job): void {
353346
$this->unlockJob($job);
354-
$this->config->setAppValue('backgroundjob', 'lastjob', (string)$job->getId());
347+
$this->config->setAppValue('backgroundjob', 'lastjob', $job->getId());
355348
}
356349

357-
/**
358-
* Remove the reservation for a job
359-
*/
350+
#[Override]
360351
public function unlockJob(IJob $job): void {
361352
$query = $this->connection->getQueryBuilder();
362353
$query->update('jobs')
@@ -365,9 +356,7 @@ public function unlockJob(IJob $job): void {
365356
$query->executeStatement();
366357
}
367358

368-
/**
369-
* set the lastRun of $job to now
370-
*/
359+
#[Override]
371360
public function setLastRun(IJob $job): void {
372361
$query = $this->connection->getQueryBuilder();
373362
$query->update('jobs')
@@ -382,9 +371,7 @@ public function setLastRun(IJob $job): void {
382371
$query->executeStatement();
383372
}
384373

385-
/**
386-
* @param int $timeTaken
387-
*/
374+
#[Override]
388375
public function setExecutionTime(IJob $job, $timeTaken): void {
389376
$query = $this->connection->getQueryBuilder();
390377
$query->update('jobs')
@@ -394,11 +381,7 @@ public function setExecutionTime(IJob $job, $timeTaken): void {
394381
$query->executeStatement();
395382
}
396383

397-
/**
398-
* Reset the $job so it executes on the next trigger
399-
*
400-
* @since 23.0.0
401-
*/
384+
#[Override]
402385
public function resetBackgroundJob(IJob $job): void {
403386
$query = $this->connection->getQueryBuilder();
404387
$query->update('jobs')
@@ -408,6 +391,7 @@ public function resetBackgroundJob(IJob $job): void {
408391
$query->executeStatement();
409392
}
410393

394+
#[Override]
411395
public function hasReservedJob(?string $className = null): bool {
412396
$query = $this->connection->getQueryBuilder();
413397
$query->select('*')
@@ -430,6 +414,7 @@ public function hasReservedJob(?string $className = null): bool {
430414
}
431415
}
432416

417+
#[Override]
433418
public function countByClass(): array {
434419
$query = $this->connection->getQueryBuilder();
435420
$query->select('class')
@@ -444,7 +429,7 @@ public function countByClass(): array {
444429

445430
while (($row = $result->fetch()) !== false) {
446431
/**
447-
* @var array{count:int, class:class-string} $row
432+
* @var array{count:int, class:class-string<IJob>} $row
448433
*/
449434
$jobs[] = $row;
450435
}

lib/public/BackgroundJob/IJob.php

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,43 +43,42 @@ public function start(IJobList $jobList): void;
4343

4444
/**
4545
* @since 7.0.0
46+
* @since 33.0.0 Parameter $id changed from int to string
4647
*/
47-
public function setId(int $id);
48+
public function setId(string $id): void;
4849

4950
/**
5051
* @since 7.0.0
5152
*/
52-
public function setLastRun(int $lastRun);
53+
public function setLastRun(int $lastRun): void;
5354

5455
/**
5556
* @param mixed $argument
5657
* @since 7.0.0
5758
*/
58-
public function setArgument($argument);
59+
public function setArgument(mixed $argument): void;
5960

6061
/**
6162
* Get the id of the background job
6263
* This id is determined by the job list when a job is added to the list
6364
*
64-
* @return int
6565
* @since 7.0.0
66+
* @since 33.0.0 The return type changed from int to string
6667
*/
67-
public function getId();
68+
public function getId(): string;
6869

6970
/**
7071
* Get the last time this job was run as unix timestamp
7172
*
72-
* @return int
7373
* @since 7.0.0
7474
*/
75-
public function getLastRun();
75+
public function getLastRun(): int;
7676

7777
/**
7878
* Get the argument associated with the background job
7979
* This is the argument that will be passed to the background job
8080
*
81-
* @return mixed
8281
* @since 7.0.0
8382
*/
84-
public function getArgument();
83+
public function getArgument(): mixed;
8584
}

0 commit comments

Comments
 (0)