Completed
Push — master ( 49a025...016f2f )
by
unknown
60:07 queued 24:26
created
lib/public/BackgroundJob/TimedJob.php 1 patch
Indentation   +60 added lines, -60 removed lines patch added patch discarded remove patch
@@ -19,70 +19,70 @@
 block discarded – undo
19 19
  * @since 33.0.0 removed deprecated `execute()` method
20 20
  */
21 21
 abstract class TimedJob extends Job {
22
-	protected int $interval = 0;
23
-	protected int $timeSensitivity = IJob::TIME_SENSITIVE;
22
+    protected int $interval = 0;
23
+    protected int $timeSensitivity = IJob::TIME_SENSITIVE;
24 24
 
25
-	/**
26
-	 * Set the interval for the job
27
-	 *
28
-	 * @param int $seconds the time to pass between two runs of the same job in seconds
29
-	 *
30
-	 * @since 15.0.0
31
-	 */
32
-	public function setInterval(int $seconds): void {
33
-		$this->interval = $seconds;
34
-	}
25
+    /**
26
+     * Set the interval for the job
27
+     *
28
+     * @param int $seconds the time to pass between two runs of the same job in seconds
29
+     *
30
+     * @since 15.0.0
31
+     */
32
+    public function setInterval(int $seconds): void {
33
+        $this->interval = $seconds;
34
+    }
35 35
 
36
-	/**
37
-	 * Get the interval [seconds] for the job
38
-	 *
39
-	 * @since 32.0.0
40
-	 */
41
-	public function getInterval(): int {
42
-		return $this->interval;
43
-	}
36
+    /**
37
+     * Get the interval [seconds] for the job
38
+     *
39
+     * @since 32.0.0
40
+     */
41
+    public function getInterval(): int {
42
+        return $this->interval;
43
+    }
44 44
 
45
-	/**
46
-	 * Whether the background job is time sensitive and needs to run soon after
47
-	 * the scheduled interval, of if it is okay to be delayed until a later time.
48
-	 *
49
-	 * @return bool
50
-	 * @since 24.0.0
51
-	 */
52
-	public function isTimeSensitive(): bool {
53
-		return $this->timeSensitivity === IJob::TIME_SENSITIVE;
54
-	}
45
+    /**
46
+     * Whether the background job is time sensitive and needs to run soon after
47
+     * the scheduled interval, of if it is okay to be delayed until a later time.
48
+     *
49
+     * @return bool
50
+     * @since 24.0.0
51
+     */
52
+    public function isTimeSensitive(): bool {
53
+        return $this->timeSensitivity === IJob::TIME_SENSITIVE;
54
+    }
55 55
 
56
-	/**
57
-	 * If your background job is not time sensitive (sending instant email
58
-	 * notifications, etc.) it would be nice to set it to IJob::TIME_INSENSITIVE
59
-	 * This way the execution can be delayed during high usage times.
60
-	 *
61
-	 * @param int $sensitivity
62
-	 * @psalm-param IJob::TIME_* $sensitivity
63
-	 * @return void
64
-	 * @since 24.0.0
65
-	 */
66
-	public function setTimeSensitivity(int $sensitivity): void {
67
-		if ($sensitivity !== self::TIME_SENSITIVE
68
-			&& $sensitivity !== self::TIME_INSENSITIVE) {
69
-			throw new \InvalidArgumentException('Invalid sensitivity');
70
-		}
56
+    /**
57
+     * If your background job is not time sensitive (sending instant email
58
+     * notifications, etc.) it would be nice to set it to IJob::TIME_INSENSITIVE
59
+     * This way the execution can be delayed during high usage times.
60
+     *
61
+     * @param int $sensitivity
62
+     * @psalm-param IJob::TIME_* $sensitivity
63
+     * @return void
64
+     * @since 24.0.0
65
+     */
66
+    public function setTimeSensitivity(int $sensitivity): void {
67
+        if ($sensitivity !== self::TIME_SENSITIVE
68
+            && $sensitivity !== self::TIME_INSENSITIVE) {
69
+            throw new \InvalidArgumentException('Invalid sensitivity');
70
+        }
71 71
 
72
-		$this->timeSensitivity = $sensitivity;
73
-	}
72
+        $this->timeSensitivity = $sensitivity;
73
+    }
74 74
 
75
-	/**
76
-	 * Run the job if the last run is more than the interval ago
77
-	 *
78
-	 * @since 25.0.0
79
-	 */
80
-	final public function start(IJobList $jobList): void {
81
-		if (($this->time->getTime() - $this->lastRun) > $this->interval) {
82
-			if ($this->interval >= 12 * 60 * 60 && $this->isTimeSensitive()) {
83
-				Server::get(LoggerInterface::class)->debug('TimedJob ' . get_class($this) . ' has a configured interval of ' . $this->interval . ' seconds, but is also marked as time sensitive. Please consider marking it as time insensitive to allow more sensitive jobs to run when needed.');
84
-			}
85
-			parent::start($jobList);
86
-		}
87
-	}
75
+    /**
76
+     * Run the job if the last run is more than the interval ago
77
+     *
78
+     * @since 25.0.0
79
+     */
80
+    final public function start(IJobList $jobList): void {
81
+        if (($this->time->getTime() - $this->lastRun) > $this->interval) {
82
+            if ($this->interval >= 12 * 60 * 60 && $this->isTimeSensitive()) {
83
+                Server::get(LoggerInterface::class)->debug('TimedJob ' . get_class($this) . ' has a configured interval of ' . $this->interval . ' seconds, but is also marked as time sensitive. Please consider marking it as time insensitive to allow more sensitive jobs to run when needed.');
84
+            }
85
+            parent::start($jobList);
86
+        }
87
+    }
88 88
 }
Please login to merge, or discard this patch.
lib/public/BackgroundJob/Job.php 1 patch
Indentation   +110 added lines, -110 removed lines patch added patch discarded remove patch
@@ -21,114 +21,114 @@
 block discarded – undo
21 21
  * @since 33.0.0 removed deprecated `execute()` method
22 22
  */
23 23
 abstract class Job implements IJob, IParallelAwareJob {
24
-	protected int $id = 0;
25
-	protected int $lastRun = 0;
26
-	protected mixed $argument = null;
27
-	protected bool $allowParallelRuns = true;
28
-
29
-	/**
30
-	 * @since 15.0.0
31
-	 */
32
-	public function __construct(
33
-		protected ITimeFactory $time,
34
-	) {
35
-	}
36
-
37
-	/**
38
-	 * @inheritdoc
39
-	 * @since 25.0.0
40
-	 */
41
-	public function start(IJobList $jobList): void {
42
-		$jobList->setLastRun($this);
43
-		$logger = \OCP\Server::get(LoggerInterface::class);
44
-
45
-		try {
46
-			$jobDetails = get_class($this) . ' (id: ' . $this->getId() . ', arguments: ' . json_encode($this->getArgument()) . ')';
47
-			$jobStartTime = $this->time->getTime();
48
-			$logger->debug('Starting job ' . $jobDetails, ['app' => 'cron']);
49
-			$this->run($this->argument);
50
-			$timeTaken = $this->time->getTime() - $jobStartTime;
51
-
52
-			$logger->debug('Finished job ' . $jobDetails . ' in ' . $timeTaken . ' seconds', ['app' => 'cron']);
53
-			$jobList->setExecutionTime($this, $timeTaken);
54
-		} catch (\Throwable $e) {
55
-			if ($logger) {
56
-				$logger->error('Error while running background job ' . $jobDetails, [
57
-					'app' => 'core',
58
-					'exception' => $e,
59
-				]);
60
-			}
61
-		}
62
-	}
63
-
64
-	/**
65
-	 * @since 15.0.0
66
-	 */
67
-	final public function setId(int $id) {
68
-		$this->id = $id;
69
-	}
70
-
71
-	/**
72
-	 * @since 15.0.0
73
-	 */
74
-	final public function setLastRun(int $lastRun) {
75
-		$this->lastRun = $lastRun;
76
-	}
77
-
78
-	/**
79
-	 * @since 15.0.0
80
-	 */
81
-	public function setArgument($argument) {
82
-		$this->argument = $argument;
83
-	}
84
-
85
-	/**
86
-	 * @since 15.0.0
87
-	 */
88
-	final public function getId(): int {
89
-		return $this->id;
90
-	}
91
-
92
-	/**
93
-	 * @since 15.0.0
94
-	 */
95
-	final public function getLastRun(): int {
96
-		return $this->lastRun;
97
-	}
98
-
99
-	/**
100
-	 * @since 15.0.0
101
-	 */
102
-	public function getArgument() {
103
-		return $this->argument;
104
-	}
105
-
106
-	/**
107
-	 * Set this to false to prevent two Jobs from this class from running in parallel
108
-	 *
109
-	 * @param bool $allow
110
-	 * @return void
111
-	 * @since 27.0.0
112
-	 */
113
-	public function setAllowParallelRuns(bool $allow): void {
114
-		$this->allowParallelRuns = $allow;
115
-	}
116
-
117
-	/**
118
-	 * @return bool
119
-	 * @since 27.0.0
120
-	 */
121
-	public function getAllowParallelRuns(): bool {
122
-		return $this->allowParallelRuns;
123
-	}
124
-
125
-	/**
126
-	 * The actual function that is called to run the job
127
-	 *
128
-	 * @param $argument
129
-	 * @return void
130
-	 *
131
-	 * @since 15.0.0
132
-	 */
133
-	abstract protected function run($argument);
24
+    protected int $id = 0;
25
+    protected int $lastRun = 0;
26
+    protected mixed $argument = null;
27
+    protected bool $allowParallelRuns = true;
28
+
29
+    /**
30
+     * @since 15.0.0
31
+     */
32
+    public function __construct(
33
+        protected ITimeFactory $time,
34
+    ) {
35
+    }
36
+
37
+    /**
38
+     * @inheritdoc
39
+     * @since 25.0.0
40
+     */
41
+    public function start(IJobList $jobList): void {
42
+        $jobList->setLastRun($this);
43
+        $logger = \OCP\Server::get(LoggerInterface::class);
44
+
45
+        try {
46
+            $jobDetails = get_class($this) . ' (id: ' . $this->getId() . ', arguments: ' . json_encode($this->getArgument()) . ')';
47
+            $jobStartTime = $this->time->getTime();
48
+            $logger->debug('Starting job ' . $jobDetails, ['app' => 'cron']);
49
+            $this->run($this->argument);
50
+            $timeTaken = $this->time->getTime() - $jobStartTime;
51
+
52
+            $logger->debug('Finished job ' . $jobDetails . ' in ' . $timeTaken . ' seconds', ['app' => 'cron']);
53
+            $jobList->setExecutionTime($this, $timeTaken);
54
+        } catch (\Throwable $e) {
55
+            if ($logger) {
56
+                $logger->error('Error while running background job ' . $jobDetails, [
57
+                    'app' => 'core',
58
+                    'exception' => $e,
59
+                ]);
60
+            }
61
+        }
62
+    }
63
+
64
+    /**
65
+     * @since 15.0.0
66
+     */
67
+    final public function setId(int $id) {
68
+        $this->id = $id;
69
+    }
70
+
71
+    /**
72
+     * @since 15.0.0
73
+     */
74
+    final public function setLastRun(int $lastRun) {
75
+        $this->lastRun = $lastRun;
76
+    }
77
+
78
+    /**
79
+     * @since 15.0.0
80
+     */
81
+    public function setArgument($argument) {
82
+        $this->argument = $argument;
83
+    }
84
+
85
+    /**
86
+     * @since 15.0.0
87
+     */
88
+    final public function getId(): int {
89
+        return $this->id;
90
+    }
91
+
92
+    /**
93
+     * @since 15.0.0
94
+     */
95
+    final public function getLastRun(): int {
96
+        return $this->lastRun;
97
+    }
98
+
99
+    /**
100
+     * @since 15.0.0
101
+     */
102
+    public function getArgument() {
103
+        return $this->argument;
104
+    }
105
+
106
+    /**
107
+     * Set this to false to prevent two Jobs from this class from running in parallel
108
+     *
109
+     * @param bool $allow
110
+     * @return void
111
+     * @since 27.0.0
112
+     */
113
+    public function setAllowParallelRuns(bool $allow): void {
114
+        $this->allowParallelRuns = $allow;
115
+    }
116
+
117
+    /**
118
+     * @return bool
119
+     * @since 27.0.0
120
+     */
121
+    public function getAllowParallelRuns(): bool {
122
+        return $this->allowParallelRuns;
123
+    }
124
+
125
+    /**
126
+     * The actual function that is called to run the job
127
+     *
128
+     * @param $argument
129
+     * @return void
130
+     *
131
+     * @since 15.0.0
132
+     */
133
+    abstract protected function run($argument);
134 134
 }
Please login to merge, or discard this patch.
lib/public/BackgroundJob/QueuedJob.php 1 patch
Indentation   +13 added lines, -13 removed lines patch added patch discarded remove patch
@@ -16,17 +16,17 @@
 block discarded – undo
16 16
  */
17 17
 abstract class QueuedJob extends Job {
18 18
 
19
-	/**
20
-	 * Run the job, then remove it from the joblist
21
-	 *
22
-	 * @since 25.0.0
23
-	 */
24
-	final public function start(IJobList $jobList): void {
25
-		if ($this->id) {
26
-			$jobList->removeById($this->id);
27
-		} else {
28
-			$jobList->remove($this, $this->argument);
29
-		}
30
-		parent::start($jobList);
31
-	}
19
+    /**
20
+     * Run the job, then remove it from the joblist
21
+     *
22
+     * @since 25.0.0
23
+     */
24
+    final public function start(IJobList $jobList): void {
25
+        if ($this->id) {
26
+            $jobList->removeById($this->id);
27
+        } else {
28
+            $jobList->remove($this, $this->argument);
29
+        }
30
+        parent::start($jobList);
31
+    }
32 32
 }
Please login to merge, or discard this patch.
lib/public/BackgroundJob/IJob.php 1 patch
Indentation   +57 added lines, -57 removed lines patch added patch discarded remove patch
@@ -18,68 +18,68 @@
 block discarded – undo
18 18
  * @since 33.0.0 removed deprecated `execute()` method
19 19
  */
20 20
 interface IJob {
21
-	/**
22
-	 * @since 24.0.0
23
-	 */
24
-	public const TIME_INSENSITIVE = 0;
25
-	/**
26
-	 * @since 24.0.0
27
-	 */
28
-	public const TIME_SENSITIVE = 1;
21
+    /**
22
+     * @since 24.0.0
23
+     */
24
+    public const TIME_INSENSITIVE = 0;
25
+    /**
26
+     * @since 24.0.0
27
+     */
28
+    public const TIME_SENSITIVE = 1;
29 29
 
30
-	/**
31
-	 * Start the background job with the registered argument
32
-	 *
33
-	 * This methods will take care of running the background job, of initializing
34
-	 * the state and cleaning up the job list after running the job.
35
-	 *
36
-	 * For common background job scenario, you will want to use TimedJob or QueuedJob
37
-	 * instead of overwriting this method.
38
-	 *
39
-	 * @param IJobList $jobList The job list that manages the state of this job
40
-	 * @since 25.0.0
41
-	 */
42
-	public function start(IJobList $jobList): void;
30
+    /**
31
+     * Start the background job with the registered argument
32
+     *
33
+     * This methods will take care of running the background job, of initializing
34
+     * the state and cleaning up the job list after running the job.
35
+     *
36
+     * For common background job scenario, you will want to use TimedJob or QueuedJob
37
+     * instead of overwriting this method.
38
+     *
39
+     * @param IJobList $jobList The job list that manages the state of this job
40
+     * @since 25.0.0
41
+     */
42
+    public function start(IJobList $jobList): void;
43 43
 
44
-	/**
45
-	 * @since 7.0.0
46
-	 */
47
-	public function setId(int $id);
44
+    /**
45
+     * @since 7.0.0
46
+     */
47
+    public function setId(int $id);
48 48
 
49
-	/**
50
-	 * @since 7.0.0
51
-	 */
52
-	public function setLastRun(int $lastRun);
49
+    /**
50
+     * @since 7.0.0
51
+     */
52
+    public function setLastRun(int $lastRun);
53 53
 
54
-	/**
55
-	 * @param mixed $argument
56
-	 * @since 7.0.0
57
-	 */
58
-	public function setArgument($argument);
54
+    /**
55
+     * @param mixed $argument
56
+     * @since 7.0.0
57
+     */
58
+    public function setArgument($argument);
59 59
 
60
-	/**
61
-	 * Get the id of the background job
62
-	 * This id is determined by the job list when a job is added to the list
63
-	 *
64
-	 * @return int
65
-	 * @since 7.0.0
66
-	 */
67
-	public function getId();
60
+    /**
61
+     * Get the id of the background job
62
+     * This id is determined by the job list when a job is added to the list
63
+     *
64
+     * @return int
65
+     * @since 7.0.0
66
+     */
67
+    public function getId();
68 68
 
69
-	/**
70
-	 * Get the last time this job was run as unix timestamp
71
-	 *
72
-	 * @return int
73
-	 * @since 7.0.0
74
-	 */
75
-	public function getLastRun();
69
+    /**
70
+     * Get the last time this job was run as unix timestamp
71
+     *
72
+     * @return int
73
+     * @since 7.0.0
74
+     */
75
+    public function getLastRun();
76 76
 
77
-	/**
78
-	 * Get the argument associated with the background job
79
-	 * This is the argument that will be passed to the background job
80
-	 *
81
-	 * @return mixed
82
-	 * @since 7.0.0
83
-	 */
84
-	public function getArgument();
77
+    /**
78
+     * Get the argument associated with the background job
79
+     * This is the argument that will be passed to the background job
80
+     *
81
+     * @return mixed
82
+     * @since 7.0.0
83
+     */
84
+    public function getArgument();
85 85
 }
Please login to merge, or discard this patch.
cron.php 2 patches
Indentation   +219 added lines, -219 removed lines patch added patch discarded remove patch
@@ -26,10 +26,10 @@  discard block
 block discarded – undo
26 26
 use Psr\Log\LoggerInterface;
27 27
 
28 28
 try {
29
-	require_once __DIR__ . '/lib/base.php';
29
+    require_once __DIR__ . '/lib/base.php';
30 30
 
31
-	if (isset($argv[1]) && ($argv[1] === '-h' || $argv[1] === '--help')) {
32
-		echo 'Description:
31
+    if (isset($argv[1]) && ($argv[1] === '-h' || $argv[1] === '--help')) {
32
+        echo 'Description:
33 33
   Run the background job routine
34 34
 
35 35
 Usage:
@@ -42,222 +42,222 @@  discard block
 block discarded – undo
42 42
 Options:
43 43
   -h, --help                 Display this help message
44 44
   -v, --verbose              Output more information' . PHP_EOL;
45
-		exit(0);
46
-	}
47
-
48
-	if (Util::needUpgrade()) {
49
-		Server::get(LoggerInterface::class)->debug('Update required, skipping cron', ['app' => 'cron']);
50
-		exit;
51
-	}
52
-
53
-	$config = Server::get(IConfig::class);
54
-
55
-	if ($config->getSystemValueBool('maintenance', false)) {
56
-		Server::get(LoggerInterface::class)->debug('We are in maintenance mode, skipping cron', ['app' => 'cron']);
57
-		exit;
58
-	}
59
-
60
-	// Don't do anything if Nextcloud has not been installed
61
-	if (!$config->getSystemValueBool('installed', false)) {
62
-		exit(0);
63
-	}
64
-
65
-	// load all apps to get all api routes properly setup
66
-	Server::get(IAppManager::class)->loadApps();
67
-	Server::get(ISession::class)->close();
68
-
69
-	$verbose = isset($argv[1]) && ($argv[1] === '-v' || $argv[1] === '--verbose');
70
-
71
-	// initialize a dummy memory session
72
-	$session = new Memory();
73
-	$cryptoWrapper = Server::get(CryptoWrapper::class);
74
-	$session = $cryptoWrapper->wrapSession($session);
75
-	\OC::$server->setSession($session);
76
-
77
-	$logger = Server::get(LoggerInterface::class);
78
-	$appConfig = Server::get(IAppConfig::class);
79
-	$tempManager = Server::get(ITempManager::class);
80
-
81
-	$tempManager->cleanOld();
82
-
83
-	// Exit if background jobs are disabled!
84
-	$appMode = $appConfig->getValueString('core', 'backgroundjobs_mode', 'ajax');
85
-	if ($appMode === 'none') {
86
-		if (OC::$CLI) {
87
-			echo 'Background Jobs are disabled!' . PHP_EOL;
88
-		} else {
89
-			OC_JSON::error(['data' => ['message' => 'Background jobs disabled!']]);
90
-		}
91
-		exit(1);
92
-	}
93
-
94
-	if (OC::$CLI) {
95
-		// set to run indefinitely if needed
96
-		if (strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
97
-			@set_time_limit(0);
98
-		}
99
-
100
-		// the cron job must be executed with the right user
101
-		if (!function_exists('posix_getuid')) {
102
-			echo 'The posix extensions are required - see https://www.php.net/manual/en/book.posix.php' . PHP_EOL;
103
-			exit(1);
104
-		}
105
-
106
-		$user = posix_getuid();
107
-		$configUser = fileowner(OC::$configDir . 'config.php');
108
-		if ($user !== $configUser) {
109
-			echo 'Console has to be executed with the user that owns the file config/config.php' . PHP_EOL;
110
-			echo 'Current user id: ' . $user . PHP_EOL;
111
-			echo 'Owner id of config.php: ' . $configUser . PHP_EOL;
112
-			exit(1);
113
-		}
114
-
115
-
116
-		// We call Nextcloud from the CLI (aka cron)
117
-		if ($appMode !== 'cron') {
118
-			$appConfig->setValueString('core', 'backgroundjobs_mode', 'cron');
119
-		}
120
-
121
-		// a specific job class list can optionally be given as argument
122
-		$jobClasses = array_slice($argv, $verbose ? 2 : 1);
123
-		$jobClasses = empty($jobClasses) ? null : $jobClasses;
124
-
125
-		// Low-load hours
126
-		$onlyTimeSensitive = false;
127
-		$startHour = $config->getSystemValueInt('maintenance_window_start', 100);
128
-		if ($jobClasses === null && $startHour <= 23) {
129
-			$date = new \DateTime('now', new \DateTimeZone('UTC'));
130
-			$currentHour = (int)$date->format('G');
131
-			$endHour = $startHour + 4;
132
-
133
-			if ($startHour <= 20) {
134
-				// Start time: 01:00
135
-				// End time: 05:00
136
-				// Only run sensitive tasks when it's before the start or after the end
137
-				$onlyTimeSensitive = $currentHour < $startHour || $currentHour > $endHour;
138
-			} else {
139
-				// Start time: 23:00
140
-				// End time: 03:00
141
-				$endHour -= 24; // Correct the end time from 27:00 to 03:00
142
-				// Only run sensitive tasks when it's after the end and before the start
143
-				$onlyTimeSensitive = $currentHour > $endHour && $currentHour < $startHour;
144
-			}
145
-		}
146
-
147
-		// Work
148
-		$jobList = Server::get(IJobList::class);
149
-
150
-		// We only ask for jobs for 14 minutes, because after 5 minutes the next
151
-		// system cron task should spawn and we want to have at most three
152
-		// cron jobs running in parallel.
153
-		$endTime = time() + 14 * 60;
154
-
155
-		$executedJobs = [];
156
-
157
-		while ($job = $jobList->getNext($onlyTimeSensitive, $jobClasses)) {
158
-			if (isset($executedJobs[$job->getId()])) {
159
-				$jobList->unlockJob($job);
160
-				break;
161
-			}
162
-
163
-			$jobDetails = get_class($job) . ' (id: ' . $job->getId() . ', arguments: ' . json_encode($job->getArgument()) . ')';
164
-			$logger->debug('CLI cron call has selected job ' . $jobDetails, ['app' => 'cron']);
165
-
166
-			$timeBefore = time();
167
-			$memoryBefore = memory_get_usage();
168
-			$memoryPeakBefore = memory_get_peak_usage();
169
-
170
-			if ($verbose) {
171
-				echo 'Starting job ' . $jobDetails . PHP_EOL;
172
-			}
173
-
174
-			$job->start($jobList);
175
-
176
-			$timeAfter = time();
177
-			$memoryAfter = memory_get_usage();
178
-			$memoryPeakAfter = memory_get_peak_usage();
179
-
180
-			$cronInterval = 5 * 60;
181
-			$timeSpent = $timeAfter - $timeBefore;
182
-			if ($timeSpent > $cronInterval) {
183
-				$logLevel = match (true) {
184
-					$timeSpent > $cronInterval * 128 => ILogger::FATAL,
185
-					$timeSpent > $cronInterval * 64 => ILogger::ERROR,
186
-					$timeSpent > $cronInterval * 16 => ILogger::WARN,
187
-					$timeSpent > $cronInterval * 8 => ILogger::INFO,
188
-					default => ILogger::DEBUG,
189
-				};
190
-				$logger->log(
191
-					$logLevel,
192
-					'Background job ' . $jobDetails . ' ran for ' . $timeSpent . ' seconds',
193
-					['app' => 'cron']
194
-				);
195
-			}
196
-
197
-			if ($memoryAfter - $memoryBefore > 50_000_000) {
198
-				$message = 'Used memory grew by more than 50 MB when executing job ' . $jobDetails . ': ' . Util::humanFileSize($memoryAfter) . ' (before: ' . Util::humanFileSize($memoryBefore) . ')';
199
-				$logger->warning($message, ['app' => 'cron']);
200
-				if ($verbose) {
201
-					echo $message . PHP_EOL;
202
-				}
203
-			}
204
-			if ($memoryPeakAfter > 300_000_000 && $memoryPeakBefore <= 300_000_000) {
205
-				$message = 'Cron job used more than 300 MB of ram after executing job ' . $jobDetails . ': ' . Util::humanFileSize($memoryPeakAfter) . ' (before: ' . Util::humanFileSize($memoryPeakBefore) . ')';
206
-				$logger->warning($message, ['app' => 'cron']);
207
-				if ($verbose) {
208
-					echo $message . PHP_EOL;
209
-				}
210
-			}
211
-
212
-			// clean up after unclean jobs
213
-			Server::get(SetupManager::class)->tearDown();
214
-			$tempManager->clean();
215
-
216
-			if ($verbose) {
217
-				echo 'Job ' . $jobDetails . ' done in ' . ($timeAfter - $timeBefore) . ' seconds' . PHP_EOL;
218
-			}
219
-
220
-			$jobList->setLastJob($job);
221
-			$executedJobs[$job->getId()] = true;
222
-			unset($job);
223
-
224
-			if ($timeAfter > $endTime) {
225
-				break;
226
-			}
227
-		}
228
-	} else {
229
-		// We call cron.php from some website
230
-		if ($appMode === 'cron') {
231
-			// Cron is cron :-P
232
-			OC_JSON::error(['data' => ['message' => 'Backgroundjobs are using system cron!']]);
233
-		} else {
234
-			// Work and success :-)
235
-			$jobList = Server::get(IJobList::class);
236
-			$job = $jobList->getNext();
237
-			if ($job != null) {
238
-				$logger->debug('WebCron call has selected job with ID ' . strval($job->getId()), ['app' => 'cron']);
239
-				$job->start($jobList);
240
-				$jobList->setLastJob($job);
241
-			}
242
-			OC_JSON::success();
243
-		}
244
-	}
245
-
246
-	// Log the successful cron execution
247
-	$appConfig->setValueInt('core', 'lastcron', time());
248
-	exit();
45
+        exit(0);
46
+    }
47
+
48
+    if (Util::needUpgrade()) {
49
+        Server::get(LoggerInterface::class)->debug('Update required, skipping cron', ['app' => 'cron']);
50
+        exit;
51
+    }
52
+
53
+    $config = Server::get(IConfig::class);
54
+
55
+    if ($config->getSystemValueBool('maintenance', false)) {
56
+        Server::get(LoggerInterface::class)->debug('We are in maintenance mode, skipping cron', ['app' => 'cron']);
57
+        exit;
58
+    }
59
+
60
+    // Don't do anything if Nextcloud has not been installed
61
+    if (!$config->getSystemValueBool('installed', false)) {
62
+        exit(0);
63
+    }
64
+
65
+    // load all apps to get all api routes properly setup
66
+    Server::get(IAppManager::class)->loadApps();
67
+    Server::get(ISession::class)->close();
68
+
69
+    $verbose = isset($argv[1]) && ($argv[1] === '-v' || $argv[1] === '--verbose');
70
+
71
+    // initialize a dummy memory session
72
+    $session = new Memory();
73
+    $cryptoWrapper = Server::get(CryptoWrapper::class);
74
+    $session = $cryptoWrapper->wrapSession($session);
75
+    \OC::$server->setSession($session);
76
+
77
+    $logger = Server::get(LoggerInterface::class);
78
+    $appConfig = Server::get(IAppConfig::class);
79
+    $tempManager = Server::get(ITempManager::class);
80
+
81
+    $tempManager->cleanOld();
82
+
83
+    // Exit if background jobs are disabled!
84
+    $appMode = $appConfig->getValueString('core', 'backgroundjobs_mode', 'ajax');
85
+    if ($appMode === 'none') {
86
+        if (OC::$CLI) {
87
+            echo 'Background Jobs are disabled!' . PHP_EOL;
88
+        } else {
89
+            OC_JSON::error(['data' => ['message' => 'Background jobs disabled!']]);
90
+        }
91
+        exit(1);
92
+    }
93
+
94
+    if (OC::$CLI) {
95
+        // set to run indefinitely if needed
96
+        if (strpos(@ini_get('disable_functions'), 'set_time_limit') === false) {
97
+            @set_time_limit(0);
98
+        }
99
+
100
+        // the cron job must be executed with the right user
101
+        if (!function_exists('posix_getuid')) {
102
+            echo 'The posix extensions are required - see https://www.php.net/manual/en/book.posix.php' . PHP_EOL;
103
+            exit(1);
104
+        }
105
+
106
+        $user = posix_getuid();
107
+        $configUser = fileowner(OC::$configDir . 'config.php');
108
+        if ($user !== $configUser) {
109
+            echo 'Console has to be executed with the user that owns the file config/config.php' . PHP_EOL;
110
+            echo 'Current user id: ' . $user . PHP_EOL;
111
+            echo 'Owner id of config.php: ' . $configUser . PHP_EOL;
112
+            exit(1);
113
+        }
114
+
115
+
116
+        // We call Nextcloud from the CLI (aka cron)
117
+        if ($appMode !== 'cron') {
118
+            $appConfig->setValueString('core', 'backgroundjobs_mode', 'cron');
119
+        }
120
+
121
+        // a specific job class list can optionally be given as argument
122
+        $jobClasses = array_slice($argv, $verbose ? 2 : 1);
123
+        $jobClasses = empty($jobClasses) ? null : $jobClasses;
124
+
125
+        // Low-load hours
126
+        $onlyTimeSensitive = false;
127
+        $startHour = $config->getSystemValueInt('maintenance_window_start', 100);
128
+        if ($jobClasses === null && $startHour <= 23) {
129
+            $date = new \DateTime('now', new \DateTimeZone('UTC'));
130
+            $currentHour = (int)$date->format('G');
131
+            $endHour = $startHour + 4;
132
+
133
+            if ($startHour <= 20) {
134
+                // Start time: 01:00
135
+                // End time: 05:00
136
+                // Only run sensitive tasks when it's before the start or after the end
137
+                $onlyTimeSensitive = $currentHour < $startHour || $currentHour > $endHour;
138
+            } else {
139
+                // Start time: 23:00
140
+                // End time: 03:00
141
+                $endHour -= 24; // Correct the end time from 27:00 to 03:00
142
+                // Only run sensitive tasks when it's after the end and before the start
143
+                $onlyTimeSensitive = $currentHour > $endHour && $currentHour < $startHour;
144
+            }
145
+        }
146
+
147
+        // Work
148
+        $jobList = Server::get(IJobList::class);
149
+
150
+        // We only ask for jobs for 14 minutes, because after 5 minutes the next
151
+        // system cron task should spawn and we want to have at most three
152
+        // cron jobs running in parallel.
153
+        $endTime = time() + 14 * 60;
154
+
155
+        $executedJobs = [];
156
+
157
+        while ($job = $jobList->getNext($onlyTimeSensitive, $jobClasses)) {
158
+            if (isset($executedJobs[$job->getId()])) {
159
+                $jobList->unlockJob($job);
160
+                break;
161
+            }
162
+
163
+            $jobDetails = get_class($job) . ' (id: ' . $job->getId() . ', arguments: ' . json_encode($job->getArgument()) . ')';
164
+            $logger->debug('CLI cron call has selected job ' . $jobDetails, ['app' => 'cron']);
165
+
166
+            $timeBefore = time();
167
+            $memoryBefore = memory_get_usage();
168
+            $memoryPeakBefore = memory_get_peak_usage();
169
+
170
+            if ($verbose) {
171
+                echo 'Starting job ' . $jobDetails . PHP_EOL;
172
+            }
173
+
174
+            $job->start($jobList);
175
+
176
+            $timeAfter = time();
177
+            $memoryAfter = memory_get_usage();
178
+            $memoryPeakAfter = memory_get_peak_usage();
179
+
180
+            $cronInterval = 5 * 60;
181
+            $timeSpent = $timeAfter - $timeBefore;
182
+            if ($timeSpent > $cronInterval) {
183
+                $logLevel = match (true) {
184
+                    $timeSpent > $cronInterval * 128 => ILogger::FATAL,
185
+                    $timeSpent > $cronInterval * 64 => ILogger::ERROR,
186
+                    $timeSpent > $cronInterval * 16 => ILogger::WARN,
187
+                    $timeSpent > $cronInterval * 8 => ILogger::INFO,
188
+                    default => ILogger::DEBUG,
189
+                };
190
+                $logger->log(
191
+                    $logLevel,
192
+                    'Background job ' . $jobDetails . ' ran for ' . $timeSpent . ' seconds',
193
+                    ['app' => 'cron']
194
+                );
195
+            }
196
+
197
+            if ($memoryAfter - $memoryBefore > 50_000_000) {
198
+                $message = 'Used memory grew by more than 50 MB when executing job ' . $jobDetails . ': ' . Util::humanFileSize($memoryAfter) . ' (before: ' . Util::humanFileSize($memoryBefore) . ')';
199
+                $logger->warning($message, ['app' => 'cron']);
200
+                if ($verbose) {
201
+                    echo $message . PHP_EOL;
202
+                }
203
+            }
204
+            if ($memoryPeakAfter > 300_000_000 && $memoryPeakBefore <= 300_000_000) {
205
+                $message = 'Cron job used more than 300 MB of ram after executing job ' . $jobDetails . ': ' . Util::humanFileSize($memoryPeakAfter) . ' (before: ' . Util::humanFileSize($memoryPeakBefore) . ')';
206
+                $logger->warning($message, ['app' => 'cron']);
207
+                if ($verbose) {
208
+                    echo $message . PHP_EOL;
209
+                }
210
+            }
211
+
212
+            // clean up after unclean jobs
213
+            Server::get(SetupManager::class)->tearDown();
214
+            $tempManager->clean();
215
+
216
+            if ($verbose) {
217
+                echo 'Job ' . $jobDetails . ' done in ' . ($timeAfter - $timeBefore) . ' seconds' . PHP_EOL;
218
+            }
219
+
220
+            $jobList->setLastJob($job);
221
+            $executedJobs[$job->getId()] = true;
222
+            unset($job);
223
+
224
+            if ($timeAfter > $endTime) {
225
+                break;
226
+            }
227
+        }
228
+    } else {
229
+        // We call cron.php from some website
230
+        if ($appMode === 'cron') {
231
+            // Cron is cron :-P
232
+            OC_JSON::error(['data' => ['message' => 'Backgroundjobs are using system cron!']]);
233
+        } else {
234
+            // Work and success :-)
235
+            $jobList = Server::get(IJobList::class);
236
+            $job = $jobList->getNext();
237
+            if ($job != null) {
238
+                $logger->debug('WebCron call has selected job with ID ' . strval($job->getId()), ['app' => 'cron']);
239
+                $job->start($jobList);
240
+                $jobList->setLastJob($job);
241
+            }
242
+            OC_JSON::success();
243
+        }
244
+    }
245
+
246
+    // Log the successful cron execution
247
+    $appConfig->setValueInt('core', 'lastcron', time());
248
+    exit();
249 249
 } catch (Exception $ex) {
250
-	Server::get(LoggerInterface::class)->error(
251
-		$ex->getMessage(),
252
-		['app' => 'cron', 'exception' => $ex]
253
-	);
254
-	echo $ex . PHP_EOL;
255
-	exit(1);
250
+    Server::get(LoggerInterface::class)->error(
251
+        $ex->getMessage(),
252
+        ['app' => 'cron', 'exception' => $ex]
253
+    );
254
+    echo $ex . PHP_EOL;
255
+    exit(1);
256 256
 } catch (Error $ex) {
257
-	Server::get(LoggerInterface::class)->error(
258
-		$ex->getMessage(),
259
-		['app' => 'cron', 'exception' => $ex]
260
-	);
261
-	echo $ex . PHP_EOL;
262
-	exit(1);
257
+    Server::get(LoggerInterface::class)->error(
258
+        $ex->getMessage(),
259
+        ['app' => 'cron', 'exception' => $ex]
260
+    );
261
+    echo $ex . PHP_EOL;
262
+    exit(1);
263 263
 }
Please login to merge, or discard this patch.
Spacing   +21 added lines, -21 removed lines patch added patch discarded remove patch
@@ -13,7 +13,7 @@  discard block
 block discarded – undo
13 13
  * SPDX-License-Identifier: AGPL-3.0-only
14 14
  */
15 15
 
16
-require_once __DIR__ . '/lib/versioncheck.php';
16
+require_once __DIR__.'/lib/versioncheck.php';
17 17
 
18 18
 use OCP\App\IAppManager;
19 19
 use OCP\BackgroundJob\IJobList;
@@ -26,7 +26,7 @@  discard block
 block discarded – undo
26 26
 use Psr\Log\LoggerInterface;
27 27
 
28 28
 try {
29
-	require_once __DIR__ . '/lib/base.php';
29
+	require_once __DIR__.'/lib/base.php';
30 30
 
31 31
 	if (isset($argv[1]) && ($argv[1] === '-h' || $argv[1] === '--help')) {
32 32
 		echo 'Description:
@@ -84,7 +84,7 @@  discard block
 block discarded – undo
84 84
 	$appMode = $appConfig->getValueString('core', 'backgroundjobs_mode', 'ajax');
85 85
 	if ($appMode === 'none') {
86 86
 		if (OC::$CLI) {
87
-			echo 'Background Jobs are disabled!' . PHP_EOL;
87
+			echo 'Background Jobs are disabled!'.PHP_EOL;
88 88
 		} else {
89 89
 			OC_JSON::error(['data' => ['message' => 'Background jobs disabled!']]);
90 90
 		}
@@ -99,16 +99,16 @@  discard block
 block discarded – undo
99 99
 
100 100
 		// the cron job must be executed with the right user
101 101
 		if (!function_exists('posix_getuid')) {
102
-			echo 'The posix extensions are required - see https://www.php.net/manual/en/book.posix.php' . PHP_EOL;
102
+			echo 'The posix extensions are required - see https://www.php.net/manual/en/book.posix.php'.PHP_EOL;
103 103
 			exit(1);
104 104
 		}
105 105
 
106 106
 		$user = posix_getuid();
107
-		$configUser = fileowner(OC::$configDir . 'config.php');
107
+		$configUser = fileowner(OC::$configDir.'config.php');
108 108
 		if ($user !== $configUser) {
109
-			echo 'Console has to be executed with the user that owns the file config/config.php' . PHP_EOL;
110
-			echo 'Current user id: ' . $user . PHP_EOL;
111
-			echo 'Owner id of config.php: ' . $configUser . PHP_EOL;
109
+			echo 'Console has to be executed with the user that owns the file config/config.php'.PHP_EOL;
110
+			echo 'Current user id: '.$user.PHP_EOL;
111
+			echo 'Owner id of config.php: '.$configUser.PHP_EOL;
112 112
 			exit(1);
113 113
 		}
114 114
 
@@ -127,7 +127,7 @@  discard block
 block discarded – undo
127 127
 		$startHour = $config->getSystemValueInt('maintenance_window_start', 100);
128 128
 		if ($jobClasses === null && $startHour <= 23) {
129 129
 			$date = new \DateTime('now', new \DateTimeZone('UTC'));
130
-			$currentHour = (int)$date->format('G');
130
+			$currentHour = (int) $date->format('G');
131 131
 			$endHour = $startHour + 4;
132 132
 
133 133
 			if ($startHour <= 20) {
@@ -160,15 +160,15 @@  discard block
 block discarded – undo
160 160
 				break;
161 161
 			}
162 162
 
163
-			$jobDetails = get_class($job) . ' (id: ' . $job->getId() . ', arguments: ' . json_encode($job->getArgument()) . ')';
164
-			$logger->debug('CLI cron call has selected job ' . $jobDetails, ['app' => 'cron']);
163
+			$jobDetails = get_class($job).' (id: '.$job->getId().', arguments: '.json_encode($job->getArgument()).')';
164
+			$logger->debug('CLI cron call has selected job '.$jobDetails, ['app' => 'cron']);
165 165
 
166 166
 			$timeBefore = time();
167 167
 			$memoryBefore = memory_get_usage();
168 168
 			$memoryPeakBefore = memory_get_peak_usage();
169 169
 
170 170
 			if ($verbose) {
171
-				echo 'Starting job ' . $jobDetails . PHP_EOL;
171
+				echo 'Starting job '.$jobDetails.PHP_EOL;
172 172
 			}
173 173
 
174 174
 			$job->start($jobList);
@@ -189,23 +189,23 @@  discard block
 block discarded – undo
189 189
 				};
190 190
 				$logger->log(
191 191
 					$logLevel,
192
-					'Background job ' . $jobDetails . ' ran for ' . $timeSpent . ' seconds',
192
+					'Background job '.$jobDetails.' ran for '.$timeSpent.' seconds',
193 193
 					['app' => 'cron']
194 194
 				);
195 195
 			}
196 196
 
197 197
 			if ($memoryAfter - $memoryBefore > 50_000_000) {
198
-				$message = 'Used memory grew by more than 50 MB when executing job ' . $jobDetails . ': ' . Util::humanFileSize($memoryAfter) . ' (before: ' . Util::humanFileSize($memoryBefore) . ')';
198
+				$message = 'Used memory grew by more than 50 MB when executing job '.$jobDetails.': '.Util::humanFileSize($memoryAfter).' (before: '.Util::humanFileSize($memoryBefore).')';
199 199
 				$logger->warning($message, ['app' => 'cron']);
200 200
 				if ($verbose) {
201
-					echo $message . PHP_EOL;
201
+					echo $message.PHP_EOL;
202 202
 				}
203 203
 			}
204 204
 			if ($memoryPeakAfter > 300_000_000 && $memoryPeakBefore <= 300_000_000) {
205
-				$message = 'Cron job used more than 300 MB of ram after executing job ' . $jobDetails . ': ' . Util::humanFileSize($memoryPeakAfter) . ' (before: ' . Util::humanFileSize($memoryPeakBefore) . ')';
205
+				$message = 'Cron job used more than 300 MB of ram after executing job '.$jobDetails.': '.Util::humanFileSize($memoryPeakAfter).' (before: '.Util::humanFileSize($memoryPeakBefore).')';
206 206
 				$logger->warning($message, ['app' => 'cron']);
207 207
 				if ($verbose) {
208
-					echo $message . PHP_EOL;
208
+					echo $message.PHP_EOL;
209 209
 				}
210 210
 			}
211 211
 
@@ -214,7 +214,7 @@  discard block
 block discarded – undo
214 214
 			$tempManager->clean();
215 215
 
216 216
 			if ($verbose) {
217
-				echo 'Job ' . $jobDetails . ' done in ' . ($timeAfter - $timeBefore) . ' seconds' . PHP_EOL;
217
+				echo 'Job '.$jobDetails.' done in '.($timeAfter - $timeBefore).' seconds'.PHP_EOL;
218 218
 			}
219 219
 
220 220
 			$jobList->setLastJob($job);
@@ -235,7 +235,7 @@  discard block
 block discarded – undo
235 235
 			$jobList = Server::get(IJobList::class);
236 236
 			$job = $jobList->getNext();
237 237
 			if ($job != null) {
238
-				$logger->debug('WebCron call has selected job with ID ' . strval($job->getId()), ['app' => 'cron']);
238
+				$logger->debug('WebCron call has selected job with ID '.strval($job->getId()), ['app' => 'cron']);
239 239
 				$job->start($jobList);
240 240
 				$jobList->setLastJob($job);
241 241
 			}
@@ -251,13 +251,13 @@  discard block
 block discarded – undo
251 251
 		$ex->getMessage(),
252 252
 		['app' => 'cron', 'exception' => $ex]
253 253
 	);
254
-	echo $ex . PHP_EOL;
254
+	echo $ex.PHP_EOL;
255 255
 	exit(1);
256 256
 } catch (Error $ex) {
257 257
 	Server::get(LoggerInterface::class)->error(
258 258
 		$ex->getMessage(),
259 259
 		['app' => 'cron', 'exception' => $ex]
260 260
 	);
261
-	echo $ex . PHP_EOL;
261
+	echo $ex.PHP_EOL;
262 262
 	exit(1);
263 263
 }
Please login to merge, or discard this patch.
core/Command/Background/JobWorker.php 2 patches
Indentation   +151 added lines, -151 removed lines patch added patch discarded remove patch
@@ -20,155 +20,155 @@
 block discarded – undo
20 20
 
21 21
 class JobWorker extends JobBase {
22 22
 
23
-	public function __construct(
24
-		protected IJobList $jobList,
25
-		protected LoggerInterface $logger,
26
-		private ITempManager $tempManager,
27
-		private SetupManager $setupManager,
28
-	) {
29
-		parent::__construct($jobList, $logger);
30
-	}
31
-	protected function configure(): void {
32
-		parent::configure();
33
-
34
-		$this
35
-			->setName('background-job:worker')
36
-			->setDescription('Run a background job worker')
37
-			->addArgument(
38
-				'job-classes',
39
-				InputArgument::OPTIONAL | InputArgument::IS_ARRAY,
40
-				'The classes of the jobs to look for in the database'
41
-			)
42
-			->addOption(
43
-				'once',
44
-				null,
45
-				InputOption::VALUE_NONE,
46
-				'Only execute the worker once (as a regular cron execution would do it)'
47
-			)
48
-			->addOption(
49
-				'interval',
50
-				'i',
51
-				InputOption::VALUE_OPTIONAL,
52
-				'Interval in seconds in which the worker should repeat already processed jobs (set to 0 for no repeat)',
53
-				5
54
-			)
55
-			->addOption(
56
-				'stop_after',
57
-				't',
58
-				InputOption::VALUE_OPTIONAL,
59
-				'Duration after which the worker should stop and exit. The worker won\'t kill a potential running job, it will exit after this job has finished running (supported values are: "30" or "30s" for 30 seconds, "10m" for 10 minutes and "2h" for 2 hours)'
60
-			)
61
-		;
62
-	}
63
-
64
-	protected function execute(InputInterface $input, OutputInterface $output): int {
65
-		$startTime = time();
66
-		$stopAfterOptionValue = $input->getOption('stop_after');
67
-		$stopAfterSeconds = $stopAfterOptionValue === null
68
-			? null
69
-			: $this->parseStopAfter($stopAfterOptionValue);
70
-		if ($stopAfterSeconds !== null) {
71
-			$output->writeln('<info>Background job worker will stop after ' . $stopAfterSeconds . ' seconds</info>');
72
-		}
73
-
74
-		$jobClasses = $input->getArgument('job-classes');
75
-		$jobClasses = empty($jobClasses) ? null : $jobClasses;
76
-
77
-		if ($jobClasses !== null) {
78
-			// at least one class is invalid
79
-			foreach ($jobClasses as $jobClass) {
80
-				if (!class_exists($jobClass)) {
81
-					$output->writeln('<error>Invalid job class: ' . $jobClass . '</error>');
82
-					return 1;
83
-				}
84
-			}
85
-		}
86
-
87
-		while (true) {
88
-			// Stop if we exceeded stop_after value
89
-			if ($stopAfterSeconds !== null && ($startTime + $stopAfterSeconds) < time()) {
90
-				$output->writeln('stop_after time has been exceeded, exiting...', OutputInterface::VERBOSITY_VERBOSE);
91
-				break;
92
-			}
93
-			// Handle canceling of the process
94
-			try {
95
-				$this->abortIfInterrupted();
96
-			} catch (InterruptedException $e) {
97
-				$output->writeln('<info>Background job worker stopped</info>');
98
-				break;
99
-			}
100
-
101
-			$this->printSummary($input, $output);
102
-
103
-			usleep(50000);
104
-			$job = $this->jobList->getNext(false, $jobClasses);
105
-			if (!$job) {
106
-				if ($input->getOption('once') === true) {
107
-					if ($jobClasses === null) {
108
-						$output->writeln('No job is currently queued', OutputInterface::VERBOSITY_VERBOSE);
109
-					} else {
110
-						$output->writeln('No job of classes [' . implode(', ', $jobClasses) . '] is currently queued', OutputInterface::VERBOSITY_VERBOSE);
111
-					}
112
-					$output->writeln('Exiting...', OutputInterface::VERBOSITY_VERBOSE);
113
-					break;
114
-				}
115
-
116
-				$output->writeln('Waiting for new jobs to be queued', OutputInterface::VERBOSITY_VERBOSE);
117
-				// Re-check interval for new jobs
118
-				sleep(1);
119
-				continue;
120
-			}
121
-
122
-			$output->writeln('Running job ' . get_class($job) . ' with ID ' . $job->getId());
123
-
124
-			if ($output->isVerbose()) {
125
-				$this->printJobInfo($job->getId(), $job, $output);
126
-			}
127
-
128
-			$job->start($this->jobList);
129
-			$output->writeln('Job ' . $job->getId() . ' has finished', OutputInterface::VERBOSITY_VERBOSE);
130
-
131
-			// clean up after unclean jobs
132
-			$this->setupManager->tearDown();
133
-			$this->tempManager->clean();
134
-
135
-			$this->jobList->setLastJob($job);
136
-			$this->jobList->unlockJob($job);
137
-
138
-			if ($input->getOption('once') === true) {
139
-				break;
140
-			}
141
-		}
142
-
143
-		return 0;
144
-	}
145
-
146
-	private function printSummary(InputInterface $input, OutputInterface $output): void {
147
-		if (!$output->isVeryVerbose()) {
148
-			return;
149
-		}
150
-		$output->writeln('<comment>Summary</comment>');
151
-
152
-		$counts = [];
153
-		foreach ($this->jobList->countByClass() as $row) {
154
-			$counts[] = $row;
155
-		}
156
-		$this->writeTableInOutputFormat($input, $output, $counts);
157
-	}
158
-
159
-	private function parseStopAfter(string $value): ?int {
160
-		if (is_numeric($value)) {
161
-			return (int)$value;
162
-		}
163
-		if (preg_match("/^(\d+)s$/i", $value, $matches)) {
164
-			return (int)$matches[0];
165
-		}
166
-		if (preg_match("/^(\d+)m$/i", $value, $matches)) {
167
-			return 60 * ((int)$matches[0]);
168
-		}
169
-		if (preg_match("/^(\d+)h$/i", $value, $matches)) {
170
-			return 60 * 60 * ((int)$matches[0]);
171
-		}
172
-		return null;
173
-	}
23
+    public function __construct(
24
+        protected IJobList $jobList,
25
+        protected LoggerInterface $logger,
26
+        private ITempManager $tempManager,
27
+        private SetupManager $setupManager,
28
+    ) {
29
+        parent::__construct($jobList, $logger);
30
+    }
31
+    protected function configure(): void {
32
+        parent::configure();
33
+
34
+        $this
35
+            ->setName('background-job:worker')
36
+            ->setDescription('Run a background job worker')
37
+            ->addArgument(
38
+                'job-classes',
39
+                InputArgument::OPTIONAL | InputArgument::IS_ARRAY,
40
+                'The classes of the jobs to look for in the database'
41
+            )
42
+            ->addOption(
43
+                'once',
44
+                null,
45
+                InputOption::VALUE_NONE,
46
+                'Only execute the worker once (as a regular cron execution would do it)'
47
+            )
48
+            ->addOption(
49
+                'interval',
50
+                'i',
51
+                InputOption::VALUE_OPTIONAL,
52
+                'Interval in seconds in which the worker should repeat already processed jobs (set to 0 for no repeat)',
53
+                5
54
+            )
55
+            ->addOption(
56
+                'stop_after',
57
+                't',
58
+                InputOption::VALUE_OPTIONAL,
59
+                'Duration after which the worker should stop and exit. The worker won\'t kill a potential running job, it will exit after this job has finished running (supported values are: "30" or "30s" for 30 seconds, "10m" for 10 minutes and "2h" for 2 hours)'
60
+            )
61
+        ;
62
+    }
63
+
64
+    protected function execute(InputInterface $input, OutputInterface $output): int {
65
+        $startTime = time();
66
+        $stopAfterOptionValue = $input->getOption('stop_after');
67
+        $stopAfterSeconds = $stopAfterOptionValue === null
68
+            ? null
69
+            : $this->parseStopAfter($stopAfterOptionValue);
70
+        if ($stopAfterSeconds !== null) {
71
+            $output->writeln('<info>Background job worker will stop after ' . $stopAfterSeconds . ' seconds</info>');
72
+        }
73
+
74
+        $jobClasses = $input->getArgument('job-classes');
75
+        $jobClasses = empty($jobClasses) ? null : $jobClasses;
76
+
77
+        if ($jobClasses !== null) {
78
+            // at least one class is invalid
79
+            foreach ($jobClasses as $jobClass) {
80
+                if (!class_exists($jobClass)) {
81
+                    $output->writeln('<error>Invalid job class: ' . $jobClass . '</error>');
82
+                    return 1;
83
+                }
84
+            }
85
+        }
86
+
87
+        while (true) {
88
+            // Stop if we exceeded stop_after value
89
+            if ($stopAfterSeconds !== null && ($startTime + $stopAfterSeconds) < time()) {
90
+                $output->writeln('stop_after time has been exceeded, exiting...', OutputInterface::VERBOSITY_VERBOSE);
91
+                break;
92
+            }
93
+            // Handle canceling of the process
94
+            try {
95
+                $this->abortIfInterrupted();
96
+            } catch (InterruptedException $e) {
97
+                $output->writeln('<info>Background job worker stopped</info>');
98
+                break;
99
+            }
100
+
101
+            $this->printSummary($input, $output);
102
+
103
+            usleep(50000);
104
+            $job = $this->jobList->getNext(false, $jobClasses);
105
+            if (!$job) {
106
+                if ($input->getOption('once') === true) {
107
+                    if ($jobClasses === null) {
108
+                        $output->writeln('No job is currently queued', OutputInterface::VERBOSITY_VERBOSE);
109
+                    } else {
110
+                        $output->writeln('No job of classes [' . implode(', ', $jobClasses) . '] is currently queued', OutputInterface::VERBOSITY_VERBOSE);
111
+                    }
112
+                    $output->writeln('Exiting...', OutputInterface::VERBOSITY_VERBOSE);
113
+                    break;
114
+                }
115
+
116
+                $output->writeln('Waiting for new jobs to be queued', OutputInterface::VERBOSITY_VERBOSE);
117
+                // Re-check interval for new jobs
118
+                sleep(1);
119
+                continue;
120
+            }
121
+
122
+            $output->writeln('Running job ' . get_class($job) . ' with ID ' . $job->getId());
123
+
124
+            if ($output->isVerbose()) {
125
+                $this->printJobInfo($job->getId(), $job, $output);
126
+            }
127
+
128
+            $job->start($this->jobList);
129
+            $output->writeln('Job ' . $job->getId() . ' has finished', OutputInterface::VERBOSITY_VERBOSE);
130
+
131
+            // clean up after unclean jobs
132
+            $this->setupManager->tearDown();
133
+            $this->tempManager->clean();
134
+
135
+            $this->jobList->setLastJob($job);
136
+            $this->jobList->unlockJob($job);
137
+
138
+            if ($input->getOption('once') === true) {
139
+                break;
140
+            }
141
+        }
142
+
143
+        return 0;
144
+    }
145
+
146
+    private function printSummary(InputInterface $input, OutputInterface $output): void {
147
+        if (!$output->isVeryVerbose()) {
148
+            return;
149
+        }
150
+        $output->writeln('<comment>Summary</comment>');
151
+
152
+        $counts = [];
153
+        foreach ($this->jobList->countByClass() as $row) {
154
+            $counts[] = $row;
155
+        }
156
+        $this->writeTableInOutputFormat($input, $output, $counts);
157
+    }
158
+
159
+    private function parseStopAfter(string $value): ?int {
160
+        if (is_numeric($value)) {
161
+            return (int)$value;
162
+        }
163
+        if (preg_match("/^(\d+)s$/i", $value, $matches)) {
164
+            return (int)$matches[0];
165
+        }
166
+        if (preg_match("/^(\d+)m$/i", $value, $matches)) {
167
+            return 60 * ((int)$matches[0]);
168
+        }
169
+        if (preg_match("/^(\d+)h$/i", $value, $matches)) {
170
+            return 60 * 60 * ((int)$matches[0]);
171
+        }
172
+        return null;
173
+    }
174 174
 }
Please login to merge, or discard this patch.
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -68,7 +68,7 @@  discard block
 block discarded – undo
68 68
 			? null
69 69
 			: $this->parseStopAfter($stopAfterOptionValue);
70 70
 		if ($stopAfterSeconds !== null) {
71
-			$output->writeln('<info>Background job worker will stop after ' . $stopAfterSeconds . ' seconds</info>');
71
+			$output->writeln('<info>Background job worker will stop after '.$stopAfterSeconds.' seconds</info>');
72 72
 		}
73 73
 
74 74
 		$jobClasses = $input->getArgument('job-classes');
@@ -78,7 +78,7 @@  discard block
 block discarded – undo
78 78
 			// at least one class is invalid
79 79
 			foreach ($jobClasses as $jobClass) {
80 80
 				if (!class_exists($jobClass)) {
81
-					$output->writeln('<error>Invalid job class: ' . $jobClass . '</error>');
81
+					$output->writeln('<error>Invalid job class: '.$jobClass.'</error>');
82 82
 					return 1;
83 83
 				}
84 84
 			}
@@ -107,7 +107,7 @@  discard block
 block discarded – undo
107 107
 					if ($jobClasses === null) {
108 108
 						$output->writeln('No job is currently queued', OutputInterface::VERBOSITY_VERBOSE);
109 109
 					} else {
110
-						$output->writeln('No job of classes [' . implode(', ', $jobClasses) . '] is currently queued', OutputInterface::VERBOSITY_VERBOSE);
110
+						$output->writeln('No job of classes ['.implode(', ', $jobClasses).'] is currently queued', OutputInterface::VERBOSITY_VERBOSE);
111 111
 					}
112 112
 					$output->writeln('Exiting...', OutputInterface::VERBOSITY_VERBOSE);
113 113
 					break;
@@ -119,14 +119,14 @@  discard block
 block discarded – undo
119 119
 				continue;
120 120
 			}
121 121
 
122
-			$output->writeln('Running job ' . get_class($job) . ' with ID ' . $job->getId());
122
+			$output->writeln('Running job '.get_class($job).' with ID '.$job->getId());
123 123
 
124 124
 			if ($output->isVerbose()) {
125 125
 				$this->printJobInfo($job->getId(), $job, $output);
126 126
 			}
127 127
 
128 128
 			$job->start($this->jobList);
129
-			$output->writeln('Job ' . $job->getId() . ' has finished', OutputInterface::VERBOSITY_VERBOSE);
129
+			$output->writeln('Job '.$job->getId().' has finished', OutputInterface::VERBOSITY_VERBOSE);
130 130
 
131 131
 			// clean up after unclean jobs
132 132
 			$this->setupManager->tearDown();
@@ -158,16 +158,16 @@  discard block
 block discarded – undo
158 158
 
159 159
 	private function parseStopAfter(string $value): ?int {
160 160
 		if (is_numeric($value)) {
161
-			return (int)$value;
161
+			return (int) $value;
162 162
 		}
163 163
 		if (preg_match("/^(\d+)s$/i", $value, $matches)) {
164
-			return (int)$matches[0];
164
+			return (int) $matches[0];
165 165
 		}
166 166
 		if (preg_match("/^(\d+)m$/i", $value, $matches)) {
167
-			return 60 * ((int)$matches[0]);
167
+			return 60 * ((int) $matches[0]);
168 168
 		}
169 169
 		if (preg_match("/^(\d+)h$/i", $value, $matches)) {
170
-			return 60 * 60 * ((int)$matches[0]);
170
+			return 60 * 60 * ((int) $matches[0]);
171 171
 		}
172 172
 		return null;
173 173
 	}
Please login to merge, or discard this patch.
core/Command/Background/Job.php 2 patches
Indentation   +116 added lines, -116 removed lines patch added patch discarded remove patch
@@ -19,120 +19,120 @@
 block discarded – undo
19 19
 use Symfony\Component\Console\Output\OutputInterface;
20 20
 
21 21
 class Job extends Command {
22
-	public function __construct(
23
-		protected IJobList $jobList,
24
-	) {
25
-		parent::__construct();
26
-	}
27
-
28
-	protected function configure(): void {
29
-		$this
30
-			->setName('background-job:execute')
31
-			->setDescription('Execute a single background job manually')
32
-			->addArgument(
33
-				'job-id',
34
-				InputArgument::REQUIRED,
35
-				'The ID of the job in the database'
36
-			)
37
-			->addOption(
38
-				'force-execute',
39
-				null,
40
-				InputOption::VALUE_NONE,
41
-				'Force execute the background job, independent from last run and being reserved'
42
-			)
43
-		;
44
-	}
45
-
46
-	protected function execute(InputInterface $input, OutputInterface $output): int {
47
-		$jobId = (int)$input->getArgument('job-id');
48
-
49
-		$job = $this->jobList->getById($jobId);
50
-		if ($job === null) {
51
-			$output->writeln('<error>Job with ID ' . $jobId . ' could not be found in the database</error>');
52
-			return 1;
53
-		}
54
-
55
-		$this->printJobInfo($jobId, $job, $output);
56
-		$output->writeln('');
57
-
58
-		$lastRun = $job->getLastRun();
59
-		if ($input->getOption('force-execute')) {
60
-			$lastRun = 0;
61
-			$output->writeln('<comment>Forcing execution of the job</comment>');
62
-			$output->writeln('');
63
-
64
-			$this->jobList->resetBackgroundJob($job);
65
-		}
66
-
67
-		$job = $this->jobList->getById($jobId);
68
-		if ($job === null) {
69
-			$output->writeln('<error>Something went wrong when trying to retrieve Job with ID ' . $jobId . ' from database</error>');
70
-			return 1;
71
-		}
72
-		$job->start($this->jobList);
73
-		$job = $this->jobList->getById($jobId);
74
-
75
-		if (($job === null) || ($lastRun !== $job->getLastRun())) {
76
-			$output->writeln('<info>Job executed!</info>');
77
-			$output->writeln('');
78
-
79
-			if ($job instanceof TimedJob) {
80
-				$this->printJobInfo($jobId, $job, $output);
81
-			}
82
-		} else {
83
-			$output->writeln('<comment>Job was not executed because it is not due</comment>');
84
-			$output->writeln('Specify the <question>--force-execute</question> option to run it anyway');
85
-		}
86
-
87
-		return 0;
88
-	}
89
-
90
-	protected function printJobInfo(int $jobId, IJob $job, OutputInterface $output): void {
91
-		$row = $this->jobList->getDetailsById($jobId);
92
-
93
-		$lastRun = new \DateTime();
94
-		$lastRun->setTimestamp((int)$row['last_run']);
95
-		$lastChecked = new \DateTime();
96
-		$lastChecked->setTimestamp((int)$row['last_checked']);
97
-		$reservedAt = new \DateTime();
98
-		$reservedAt->setTimestamp((int)$row['reserved_at']);
99
-
100
-		$output->writeln('Job class:            ' . get_class($job));
101
-		$output->writeln('Arguments:            ' . json_encode($job->getArgument()));
102
-
103
-		$isTimedJob = $job instanceof TimedJob;
104
-		if ($isTimedJob) {
105
-			$output->writeln('Type:                 timed');
106
-		} elseif ($job instanceof QueuedJob) {
107
-			$output->writeln('Type:                 queued');
108
-		} else {
109
-			$output->writeln('Type:                 job');
110
-		}
111
-
112
-		$output->writeln('');
113
-		$output->writeln('Last checked:         ' . $lastChecked->format(\DateTimeInterface::ATOM));
114
-		if ((int)$row['reserved_at'] === 0) {
115
-			$output->writeln('Reserved at:          -');
116
-		} else {
117
-			$output->writeln('Reserved at:          <comment>' . $reservedAt->format(\DateTimeInterface::ATOM) . '</comment>');
118
-		}
119
-		$output->writeln('Last executed:        ' . $lastRun->format(\DateTimeInterface::ATOM));
120
-		$output->writeln('Last duration:        ' . $row['execution_duration']);
121
-
122
-		if ($isTimedJob) {
123
-			$reflection = new \ReflectionClass($job);
124
-			$intervalProperty = $reflection->getProperty('interval');
125
-			$intervalProperty->setAccessible(true);
126
-			$interval = $intervalProperty->getValue($job);
127
-
128
-			$nextRun = new \DateTime();
129
-			$nextRun->setTimestamp($row['last_run'] + $interval);
130
-
131
-			if ($nextRun > new \DateTime()) {
132
-				$output->writeln('Next execution:       <comment>' . $nextRun->format(\DateTimeInterface::ATOM) . '</comment>');
133
-			} else {
134
-				$output->writeln('Next execution:       <info>' . $nextRun->format(\DateTimeInterface::ATOM) . '</info>');
135
-			}
136
-		}
137
-	}
22
+    public function __construct(
23
+        protected IJobList $jobList,
24
+    ) {
25
+        parent::__construct();
26
+    }
27
+
28
+    protected function configure(): void {
29
+        $this
30
+            ->setName('background-job:execute')
31
+            ->setDescription('Execute a single background job manually')
32
+            ->addArgument(
33
+                'job-id',
34
+                InputArgument::REQUIRED,
35
+                'The ID of the job in the database'
36
+            )
37
+            ->addOption(
38
+                'force-execute',
39
+                null,
40
+                InputOption::VALUE_NONE,
41
+                'Force execute the background job, independent from last run and being reserved'
42
+            )
43
+        ;
44
+    }
45
+
46
+    protected function execute(InputInterface $input, OutputInterface $output): int {
47
+        $jobId = (int)$input->getArgument('job-id');
48
+
49
+        $job = $this->jobList->getById($jobId);
50
+        if ($job === null) {
51
+            $output->writeln('<error>Job with ID ' . $jobId . ' could not be found in the database</error>');
52
+            return 1;
53
+        }
54
+
55
+        $this->printJobInfo($jobId, $job, $output);
56
+        $output->writeln('');
57
+
58
+        $lastRun = $job->getLastRun();
59
+        if ($input->getOption('force-execute')) {
60
+            $lastRun = 0;
61
+            $output->writeln('<comment>Forcing execution of the job</comment>');
62
+            $output->writeln('');
63
+
64
+            $this->jobList->resetBackgroundJob($job);
65
+        }
66
+
67
+        $job = $this->jobList->getById($jobId);
68
+        if ($job === null) {
69
+            $output->writeln('<error>Something went wrong when trying to retrieve Job with ID ' . $jobId . ' from database</error>');
70
+            return 1;
71
+        }
72
+        $job->start($this->jobList);
73
+        $job = $this->jobList->getById($jobId);
74
+
75
+        if (($job === null) || ($lastRun !== $job->getLastRun())) {
76
+            $output->writeln('<info>Job executed!</info>');
77
+            $output->writeln('');
78
+
79
+            if ($job instanceof TimedJob) {
80
+                $this->printJobInfo($jobId, $job, $output);
81
+            }
82
+        } else {
83
+            $output->writeln('<comment>Job was not executed because it is not due</comment>');
84
+            $output->writeln('Specify the <question>--force-execute</question> option to run it anyway');
85
+        }
86
+
87
+        return 0;
88
+    }
89
+
90
+    protected function printJobInfo(int $jobId, IJob $job, OutputInterface $output): void {
91
+        $row = $this->jobList->getDetailsById($jobId);
92
+
93
+        $lastRun = new \DateTime();
94
+        $lastRun->setTimestamp((int)$row['last_run']);
95
+        $lastChecked = new \DateTime();
96
+        $lastChecked->setTimestamp((int)$row['last_checked']);
97
+        $reservedAt = new \DateTime();
98
+        $reservedAt->setTimestamp((int)$row['reserved_at']);
99
+
100
+        $output->writeln('Job class:            ' . get_class($job));
101
+        $output->writeln('Arguments:            ' . json_encode($job->getArgument()));
102
+
103
+        $isTimedJob = $job instanceof TimedJob;
104
+        if ($isTimedJob) {
105
+            $output->writeln('Type:                 timed');
106
+        } elseif ($job instanceof QueuedJob) {
107
+            $output->writeln('Type:                 queued');
108
+        } else {
109
+            $output->writeln('Type:                 job');
110
+        }
111
+
112
+        $output->writeln('');
113
+        $output->writeln('Last checked:         ' . $lastChecked->format(\DateTimeInterface::ATOM));
114
+        if ((int)$row['reserved_at'] === 0) {
115
+            $output->writeln('Reserved at:          -');
116
+        } else {
117
+            $output->writeln('Reserved at:          <comment>' . $reservedAt->format(\DateTimeInterface::ATOM) . '</comment>');
118
+        }
119
+        $output->writeln('Last executed:        ' . $lastRun->format(\DateTimeInterface::ATOM));
120
+        $output->writeln('Last duration:        ' . $row['execution_duration']);
121
+
122
+        if ($isTimedJob) {
123
+            $reflection = new \ReflectionClass($job);
124
+            $intervalProperty = $reflection->getProperty('interval');
125
+            $intervalProperty->setAccessible(true);
126
+            $interval = $intervalProperty->getValue($job);
127
+
128
+            $nextRun = new \DateTime();
129
+            $nextRun->setTimestamp($row['last_run'] + $interval);
130
+
131
+            if ($nextRun > new \DateTime()) {
132
+                $output->writeln('Next execution:       <comment>' . $nextRun->format(\DateTimeInterface::ATOM) . '</comment>');
133
+            } else {
134
+                $output->writeln('Next execution:       <info>' . $nextRun->format(\DateTimeInterface::ATOM) . '</info>');
135
+            }
136
+        }
137
+    }
138 138
 }
Please login to merge, or discard this patch.
Spacing   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -44,11 +44,11 @@  discard block
 block discarded – undo
44 44
 	}
45 45
 
46 46
 	protected function execute(InputInterface $input, OutputInterface $output): int {
47
-		$jobId = (int)$input->getArgument('job-id');
47
+		$jobId = (int) $input->getArgument('job-id');
48 48
 
49 49
 		$job = $this->jobList->getById($jobId);
50 50
 		if ($job === null) {
51
-			$output->writeln('<error>Job with ID ' . $jobId . ' could not be found in the database</error>');
51
+			$output->writeln('<error>Job with ID '.$jobId.' could not be found in the database</error>');
52 52
 			return 1;
53 53
 		}
54 54
 
@@ -66,7 +66,7 @@  discard block
 block discarded – undo
66 66
 
67 67
 		$job = $this->jobList->getById($jobId);
68 68
 		if ($job === null) {
69
-			$output->writeln('<error>Something went wrong when trying to retrieve Job with ID ' . $jobId . ' from database</error>');
69
+			$output->writeln('<error>Something went wrong when trying to retrieve Job with ID '.$jobId.' from database</error>');
70 70
 			return 1;
71 71
 		}
72 72
 		$job->start($this->jobList);
@@ -91,14 +91,14 @@  discard block
 block discarded – undo
91 91
 		$row = $this->jobList->getDetailsById($jobId);
92 92
 
93 93
 		$lastRun = new \DateTime();
94
-		$lastRun->setTimestamp((int)$row['last_run']);
94
+		$lastRun->setTimestamp((int) $row['last_run']);
95 95
 		$lastChecked = new \DateTime();
96
-		$lastChecked->setTimestamp((int)$row['last_checked']);
96
+		$lastChecked->setTimestamp((int) $row['last_checked']);
97 97
 		$reservedAt = new \DateTime();
98
-		$reservedAt->setTimestamp((int)$row['reserved_at']);
98
+		$reservedAt->setTimestamp((int) $row['reserved_at']);
99 99
 
100
-		$output->writeln('Job class:            ' . get_class($job));
101
-		$output->writeln('Arguments:            ' . json_encode($job->getArgument()));
100
+		$output->writeln('Job class:            '.get_class($job));
101
+		$output->writeln('Arguments:            '.json_encode($job->getArgument()));
102 102
 
103 103
 		$isTimedJob = $job instanceof TimedJob;
104 104
 		if ($isTimedJob) {
@@ -110,14 +110,14 @@  discard block
 block discarded – undo
110 110
 		}
111 111
 
112 112
 		$output->writeln('');
113
-		$output->writeln('Last checked:         ' . $lastChecked->format(\DateTimeInterface::ATOM));
114
-		if ((int)$row['reserved_at'] === 0) {
113
+		$output->writeln('Last checked:         '.$lastChecked->format(\DateTimeInterface::ATOM));
114
+		if ((int) $row['reserved_at'] === 0) {
115 115
 			$output->writeln('Reserved at:          -');
116 116
 		} else {
117
-			$output->writeln('Reserved at:          <comment>' . $reservedAt->format(\DateTimeInterface::ATOM) . '</comment>');
117
+			$output->writeln('Reserved at:          <comment>'.$reservedAt->format(\DateTimeInterface::ATOM).'</comment>');
118 118
 		}
119
-		$output->writeln('Last executed:        ' . $lastRun->format(\DateTimeInterface::ATOM));
120
-		$output->writeln('Last duration:        ' . $row['execution_duration']);
119
+		$output->writeln('Last executed:        '.$lastRun->format(\DateTimeInterface::ATOM));
120
+		$output->writeln('Last duration:        '.$row['execution_duration']);
121 121
 
122 122
 		if ($isTimedJob) {
123 123
 			$reflection = new \ReflectionClass($job);
@@ -129,9 +129,9 @@  discard block
 block discarded – undo
129 129
 			$nextRun->setTimestamp($row['last_run'] + $interval);
130 130
 
131 131
 			if ($nextRun > new \DateTime()) {
132
-				$output->writeln('Next execution:       <comment>' . $nextRun->format(\DateTimeInterface::ATOM) . '</comment>');
132
+				$output->writeln('Next execution:       <comment>'.$nextRun->format(\DateTimeInterface::ATOM).'</comment>');
133 133
 			} else {
134
-				$output->writeln('Next execution:       <info>' . $nextRun->format(\DateTimeInterface::ATOM) . '</info>');
134
+				$output->writeln('Next execution:       <info>'.$nextRun->format(\DateTimeInterface::ATOM).'</info>');
135 135
 			}
136 136
 		}
137 137
 	}
Please login to merge, or discard this patch.