1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OC\Core\Command\Background;
use OCP\BackgroundJob\IJob;
use OCP\BackgroundJob\IJobList;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class Job extends Command {
public function __construct(
protected IJobList $jobList,
) {
parent::__construct();
}
protected function configure(): void {
$this
->setName('background-job:execute')
->setDescription('Execute a single background job manually')
->addArgument(
'job-id',
InputArgument::REQUIRED,
'The ID of the job in the database'
)
->addOption(
'force-execute',
null,
InputOption::VALUE_NONE,
'Force execute the background job, independent from last run and being reserved'
)
;
}
protected function execute(InputInterface $input, OutputInterface $output): int {
$jobId = (int)$input->getArgument('job-id');
$job = $this->jobList->getById($jobId);
if ($job === null) {
$output->writeln('<error>Job with ID ' . $jobId . ' could not be found in the database</error>');
return 1;
}
$this->printJobInfo($jobId, $job, $output);
$output->writeln('');
$lastRun = $job->getLastRun();
if ($input->getOption('force-execute')) {
$lastRun = 0;
$output->writeln('<comment>Forcing execution of the job</comment>');
$output->writeln('');
$this->jobList->resetBackgroundJob($job);
}
$job = $this->jobList->getById($jobId);
if ($job === null) {
$output->writeln('<error>Something went wrong when trying to retrieve Job with ID ' . $jobId . ' from database</error>');
return 1;
}
/** @psalm-suppress DeprecatedMethod Calling execute until it is removed, then will switch to start */
$job->execute($this->jobList);
$job = $this->jobList->getById($jobId);
if (($job === null) || ($lastRun !== $job->getLastRun())) {
$output->writeln('<info>Job executed!</info>');
$output->writeln('');
if ($job instanceof \OCP\BackgroundJob\TimedJob) {
$this->printJobInfo($jobId, $job, $output);
}
} else {
$output->writeln('<comment>Job was not executed because it is not due</comment>');
$output->writeln('Specify the <question>--force-execute</question> option to run it anyway');
}
return 0;
}
protected function printJobInfo(int $jobId, IJob $job, OutputInterface $output): void {
$row = $this->jobList->getDetailsById($jobId);
$lastRun = new \DateTime();
$lastRun->setTimestamp((int)$row['last_run']);
$lastChecked = new \DateTime();
$lastChecked->setTimestamp((int)$row['last_checked']);
$reservedAt = new \DateTime();
$reservedAt->setTimestamp((int)$row['reserved_at']);
$output->writeln('Job class: ' . get_class($job));
$output->writeln('Arguments: ' . json_encode($job->getArgument()));
$isTimedJob = $job instanceof \OCP\BackgroundJob\TimedJob;
if ($isTimedJob) {
$output->writeln('Type: timed');
} elseif ($job instanceof \OCP\BackgroundJob\QueuedJob) {
$output->writeln('Type: queued');
} else {
$output->writeln('Type: job');
}
$output->writeln('');
$output->writeln('Last checked: ' . $lastChecked->format(\DateTimeInterface::ATOM));
if ((int)$row['reserved_at'] === 0) {
$output->writeln('Reserved at: -');
} else {
$output->writeln('Reserved at: <comment>' . $reservedAt->format(\DateTimeInterface::ATOM) . '</comment>');
}
$output->writeln('Last executed: ' . $lastRun->format(\DateTimeInterface::ATOM));
$output->writeln('Last duration: ' . $row['execution_duration']);
if ($isTimedJob) {
$reflection = new \ReflectionClass($job);
$intervalProperty = $reflection->getProperty('interval');
$intervalProperty->setAccessible(true);
$interval = $intervalProperty->getValue($job);
$nextRun = new \DateTime();
$nextRun->setTimestamp($row['last_run'] + $interval);
if ($nextRun > new \DateTime()) {
$output->writeln('Next execution: <comment>' . $nextRun->format(\DateTimeInterface::ATOM) . '</comment>');
} else {
$output->writeln('Next execution: <info>' . $nextRun->format(\DateTimeInterface::ATOM) . '</info>');
}
}
}
}
|