Skip to content

Commit 95000a1

Browse files
authored
enh: Enforce a max count of running indexer jobs (#77)
Signed-off-by: Marcel Klehr <[email protected]>
1 parent 5f411aa commit 95000a1

File tree

1 file changed

+48
-0
lines changed

1 file changed

+48
-0
lines changed

lib/BackgroundJobs/IndexerJob.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,31 @@
1919
use OCP\BackgroundJob\IJobList;
2020
use OCP\BackgroundJob\TimedJob;
2121
use OCP\DB\Exception;
22+
use OCP\DB\QueryBuilder\IQueryBuilder;
2223
use OCP\Files\Config\ICachedMountInfo;
2324
use OCP\Files\Config\IUserMountCache;
2425
use OCP\Files\File;
2526
use OCP\Files\InvalidPathException;
2627
use OCP\Files\IRootFolder;
2728
use OCP\Files\NotFoundException;
2829
use OCP\Files\NotPermittedException;
30+
use OCP\IDBConnection;
2931
use OCP\Lock\LockedException;
3032
use Psr\Log\LoggerInterface;
3133

34+
/**
35+
* Indexer Job
36+
* Makes use of the following app config settings:
37+
*
38+
* auto_indexing: bool = true The job only runs if this is true
39+
* indexing_batch_size: int = 100 The number of files to index per run
40+
* indexing_max_time: int = 30*60 The number of seconds to index files for per run, regardless of batch size
41+
* indexing_max_jobs_count: int = 3 The maximum number of Indexer jobs allowed to run at the same time
42+
*/
3243
class IndexerJob extends TimedJob {
3344

3445
public const DEFAULT_MAX_INDEXING_TIME = 30 * 60;
46+
public const DEFAULT_MAX_JOBS_COUNT = 3;
3547

3648
public function __construct(
3749
ITimeFactory $time,
@@ -44,6 +56,8 @@ public function __construct(
4456
private IRootFolder $rootFolder,
4557
private IAppConfig $appConfig,
4658
private DiagnosticService $diagnosticService,
59+
private IDBConnection $db,
60+
private ITimeFactory $timeFactory,
4761
) {
4862
parent::__construct($time);
4963
$this->setInterval($this->getMaxIndexingTime());
@@ -66,6 +80,9 @@ public function run($argument): void {
6680
if ($this->appConfig->getAppValue('auto_indexing', 'true') === 'false') {
6781
return;
6882
}
83+
if ($this->hasEnoughRunningJobs()) {
84+
return;
85+
}
6986
$this->logger->debug('Index files of storage ' . $storageId);
7087
try {
7188
$this->logger->debug('fetching ' . $this->getBatchSize() . ' files from queue');
@@ -122,6 +139,37 @@ protected function getMaxIndexingTime(): int {
122139
return $this->appConfig->getAppValueInt('indexing_max_time', self::DEFAULT_MAX_INDEXING_TIME);
123140
}
124141

142+
protected function hasEnoughRunningJobs(): bool {
143+
// Sleep a bit randomly to avoid a scenario where all jobs are started at the same time and kill themselves directly
144+
sleep(rand(1, 3 * 60));
145+
if (!$this->jobList->hasReservedJob(static::class)) {
146+
// short circuit to false if no jobs are running, yet
147+
return false;
148+
}
149+
$count = 0;
150+
foreach ($this->jobList->getJobsIterator(static::class, null, 0) as $job) {
151+
// Check if job is running
152+
$query = $this->db->getQueryBuilder();
153+
$query->select('*')
154+
->from('jobs')
155+
->where($query->expr()->gt('reserved_at', $query->createNamedParameter($this->timeFactory->getTime() - 6 * 3600, IQueryBuilder::PARAM_INT)))
156+
->andWhere($query->expr()->eq('id', $query->createNamedParameter($job->getId(), IQueryBuilder::PARAM_INT)))
157+
->setMaxResults(1);
158+
159+
try {
160+
$result = $query->executeQuery();
161+
if ($result->fetch() !== false) {
162+
// count if it's running
163+
$count++;
164+
}
165+
$result->closeCursor();
166+
} catch (Exception $e) {
167+
$this->logger->warning('Querying reserved jobs failed', ['exception' => $e]);
168+
}
169+
}
170+
return $count >= $this->appConfig->getAppValueInt('indexing_max_jobs_count', self::DEFAULT_MAX_JOBS_COUNT);
171+
}
172+
125173
/**
126174
* @param QueueFile[] $files
127175
* @return void

0 commit comments

Comments
 (0)