Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
23 / 23
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
WorkerJobCounter
100.00% covered (success)
100.00%
23 / 23
100.00% covered (success)
100.00%
3 / 3
5
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 jobClasses
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 countEligibleJobs
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3declare(strict_types=1);
4/**
5 * SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
6 * SPDX-License-Identifier: AGPL-3.0-or-later
7 */
8
9namespace OCA\Libresign\Service\Worker;
10
11use OCP\DB\QueryBuilder\IQueryBuilder;
12use OCP\IDBConnection;
13
14/**
15 * Lightweight readiness hint for the signing pool on supported Nextcloud 36.
16 * IJobList::countByClass() includes both future and reserved jobs; the public
17 * interface does not provide a read-only due-job count. Do not reserve here.
18 */
19class WorkerJobCounter {
20    public function __construct(
21        private IDBConnection $db,
22        private WorkerConfiguration $configuration,
23    ) {
24    }
25
26    /** @return list<class-string> */
27    public function jobClasses(string $pool): array {
28        return match ($pool) {
29            WorkerConfiguration::SIGNING => $this->configuration->getSigningJobClasses(),
30            WorkerConfiguration::NOTIFICATION => $this->configuration->getNotificationJobClasses(),
31            default => throw new \InvalidArgumentException('Unknown local worker pool'),
32        };
33    }
34
35    public function countEligibleJobs(int $max, string $pool = WorkerConfiguration::SIGNING): int {
36        if ($max <= 0) {
37            return 0;
38        }
39
40        $now = time();
41        $query = $this->db->getQueryBuilder();
42        $query->select('id')->from('jobs')
43            ->where($query->expr()->in('class', $query->createNamedParameter(
44                $this->jobClasses($pool), IQueryBuilder::PARAM_STR_ARRAY,
45            )))
46            ->andWhere($query->expr()->lte('reserved_at', $query->createNamedParameter($now - 12 * 3600, IQueryBuilder::PARAM_INT)))
47            ->andWhere($query->expr()->lte('last_checked', $query->createNamedParameter($now, IQueryBuilder::PARAM_INT)))
48            ->setMaxResults(min($max, 32));
49
50        $result = $query->executeQuery();
51        try {
52            $count = 0;
53            while ($result->fetchOne() !== false) {
54                $count++;
55            }
56            return $count;
57        } finally {
58            $result->closeCursor();
59        }
60    }
61}