MediaWiki master
Job.php
Go to the documentation of this file.
1<?php
7namespace MediaWiki\JobQueue;
8
9use InvalidArgumentException;
15
27abstract class Job implements RunnableJob {
29 public $command;
30
32 public $params;
33
35 public $metadata = [];
36
38 protected $title;
39
41 protected $removeDuplicates = false;
42
44 protected $error;
45
47 protected $teardownCallbacks = [];
48
50 protected $executionFlags = 0;
51
61 public static function factory( $command, $params = [] ) {
62 $factory = MediaWikiServices::getInstance()->getJobFactory();
63
64 // FIXME: fix handling for legacy signature!
65 // @phan-suppress-next-line PhanParamTooFewUnpack one argument is known to be present.
66 return $factory->newJob( ...func_get_args() );
67 }
68
76 public function __construct( $command, $params = null ) {
77 if ( $params instanceof PageReference ) {
78 // Backwards compatibility for old signature ($command, $title, $params)
79 $page = $params;
80 $params = func_num_args() >= 3 ? func_get_arg( 2 ) : [];
81 } else {
82 // Newer jobs may choose to not have a top-level title (e.g. GenericParameterJob)
83 $page = null;
84 }
85
86 if ( !is_array( $params ) ) {
87 throw new InvalidArgumentException( '$params must be an array' );
88 }
89
90 if (
91 $page &&
92 !isset( $params['namespace'] ) &&
93 !isset( $params['title'] )
94 ) {
95 // When constructing this class for submitting to the queue,
96 // normalise the $page arg of old job classes as part of $params.
97 $params['namespace'] = $page->getNamespace();
98 $params['title'] = $page->getDBkey();
99 }
100
101 $this->command = $command;
102 $this->params = $params + [
103 'requestId' => Telemetry::getInstance()->getRequestId(),
104 ];
105
106 if ( $this->title === null ) {
107 // Set this field for access via getTitle().
108 $this->title = ( isset( $params['namespace'] ) && isset( $params['title'] ) )
109 ? Title::makeTitle( $params['namespace'], $params['title'] )
110 // GenericParameterJob classes without namespace/title params
111 // should not use getTitle(). Set an invalid title as placeholder.
113 }
114 }
115
120 public function hasExecutionFlag( $flag ) {
121 return ( $this->executionFlags & $flag ) === $flag;
122 }
123
128 public function getType() {
129 return $this->command;
130 }
131
135 final public function getTitle() {
136 return $this->title;
137 }
138
143 public function getParams() {
144 return $this->params;
145 }
146
153 public function getMetadata( $field = null ) {
154 if ( $field === null ) {
155 return $this->metadata;
156 }
157
158 return $this->metadata[$field] ?? null;
159 }
160
168 public function setMetadata( $field, $value ) {
169 $old = $this->getMetadata( $field );
170 if ( $value === null ) {
171 unset( $this->metadata[$field] );
172 } else {
173 $this->metadata[$field] = $value;
174 }
175
176 return $old;
177 }
178
184 public function getReleaseTimestamp() {
185 $time = wfTimestampOrNull( TS_UNIX, $this->params['jobReleaseTimestamp'] ?? null );
186 return $time ? (int)$time : null;
187 }
188
193 public function getQueuedTimestamp() {
194 $time = wfTimestampOrNull( TS_UNIX, $this->metadata['timestamp'] ?? null );
195 return $time ? (int)$time : null;
196 }
197
202 public function getRequestId() {
203 return $this->params['requestId'] ?? null;
204 }
205
210 public function getReadyTimestamp() {
211 return $this->getReleaseTimestamp() ?: $this->getQueuedTimestamp();
212 }
213
227 public function ignoreDuplicates() {
229 }
230
235 public function allowRetries() {
236 return true;
237 }
238
243 public function workItemCount() {
244 return 1;
245 }
246
257 public function getDeduplicationInfo() {
258 $info = [
259 'type' => $this->getType(),
260 'params' => $this->getParams()
261 ];
262 if ( is_array( $info['params'] ) ) {
263 // Identical jobs with different "root" jobs should count as duplicates
264 unset( $info['params']['rootJobSignature'] );
265 unset( $info['params']['rootJobTimestamp'] );
266 // Likewise for jobs with different delay times
267 unset( $info['params']['jobReleaseTimestamp'] );
268 // Identical jobs from different requests should count as duplicates
269 unset( $info['params']['requestId'] );
270 // Queues pack and hash this array, so normalize the order
271 ksort( $info['params'] );
272 }
273
274 return $info;
275 }
276
296 public static function newRootJobParams( $key ) {
297 return [
298 'rootJobIsSelf' => true,
299 'rootJobSignature' => sha1( $key ),
300 'rootJobTimestamp' => wfTimestampNow()
301 ];
302 }
303
310 public function getRootJobParams() {
311 return [
312 'rootJobSignature' => $this->params['rootJobSignature'] ?? null,
313 'rootJobTimestamp' => $this->params['rootJobTimestamp'] ?? null
314 ];
315 }
316
323 public function hasRootJobParams() {
324 return isset( $this->params['rootJobSignature'] )
325 && isset( $this->params['rootJobTimestamp'] );
326 }
327
333 public function isRootJob() {
334 return $this->hasRootJobParams() && !empty( $this->params['rootJobIsSelf'] );
335 }
336
343 protected function addTeardownCallback( $callback ) {
344 $this->teardownCallbacks[] = $callback;
345 }
346
351 public function teardown( $status ) {
352 foreach ( $this->teardownCallbacks as $callback ) {
353 $callback( $status );
354 }
355 }
356
361 public function toString() {
362 $paramString = '';
363 if ( $this->params ) {
364 foreach ( $this->params as $key => $value ) {
365 if ( $paramString != '' ) {
366 $paramString .= ' ';
367 }
368 if ( is_array( $value ) ) {
369 $filteredValue = [];
370 foreach ( $value as $k => $v ) {
371 $json = FormatJson::encode( $v );
372 if ( $json === false || mb_strlen( $json ) > 512 ) {
373 $filteredValue[$k] = get_debug_type( $v ) . '(...)';
374 } else {
375 $filteredValue[$k] = $v;
376 }
377 }
378 if ( count( $filteredValue ) <= 10 ) {
379 $value = FormatJson::encode( $filteredValue );
380 } else {
381 $value = "array(" . count( $value ) . ")";
382 }
383 } elseif ( is_object( $value ) && !method_exists( $value, '__toString' ) ) {
384 $value = get_debug_type( $value );
385 }
386
387 $flatValue = (string)$value;
388 if ( mb_strlen( $flatValue ) > 1024 ) {
389 $flatValue = "string(" . mb_strlen( $value ) . ")";
390 }
391
392 // Remove newline characters from the value, since
393 // newlines indicate new job lines in log files
394 $flatValue = preg_replace( '/\s+/', ' ', $flatValue );
395
396 $paramString .= "$key={$flatValue}";
397 }
398 }
399
400 $metaString = '';
401 foreach ( $this->metadata as $key => $value ) {
402 if ( is_scalar( $value ) && mb_strlen( $value ) < 1024 ) {
403 $metaString .= ( $metaString ? ",$key=$value" : "$key=$value" );
404 }
405 }
406
407 $s = $this->command;
408 if ( is_object( $this->title ) ) {
409 $s .= ' ' . $this->title->getPrefixedDBkey();
410 }
411 if ( $paramString != '' ) {
412 $s .= " $paramString";
413 }
414 if ( $metaString != '' ) {
415 $s .= " ($metaString)";
416 }
417
418 return $s;
419 }
420
424 protected function setLastError( $error ) {
425 $this->error = $error;
426 }
427
432 public function getLastError() {
433 return $this->error;
434 }
435}
436
438class_alias( Job::class, 'Job' );
const NS_SPECIAL
Definition Defines.php:40
wfTimestampOrNull( $outputtype=TS_UNIX, $ts=null)
Return a formatted timestamp, or null if input is null.
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
makeTitle( $linkId)
Convert a link ID to a Title.to override Title
Service for handling telemetry data.
Definition Telemetry.php:15
Describe and execute a background job.
Definition Job.php:27
setMetadata( $field, $value)
Definition Job.php:168
int $executionFlags
Bitfield of JOB_* class constants.
Definition Job.php:50
callable[] $teardownCallbacks
Definition Job.php:47
ignoreDuplicates()
Whether the queue should reject insertion of this job if a duplicate exists.
Definition Job.php:227
getRequestId()
string|null Id of the request that created this job. Follows jobs recursively, allowing to track the ...
Definition Job.php:202
array $params
Array of job parameters.
Definition Job.php:32
getDeduplicationInfo()
Subclasses may need to override this to make duplication detection work.
Definition Job.php:257
toString()
string Debugging string describing the job
Definition Job.php:361
getReadyTimestamp()
int|null UNIX timestamp of when the job was runnable, or null 1.26
Definition Job.php:210
addTeardownCallback( $callback)
Definition Job.php:343
teardown( $status)
Definition Job.php:351
getMetadata( $field=null)
Definition Job.php:153
getType()
string Job type that defines what sort of changes this job makes
Definition Job.php:128
allowRetries()
Whether to retry execution of this job if run() returned false or threw an exception....
Definition Job.php:235
setLastError( $error)
Definition Job.php:424
getParams()
array Parameters that specify sources, targets, and options for execution
Definition Job.php:143
hasExecutionFlag( $flag)
bool 1.31
Definition Job.php:120
bool $removeDuplicates
Expensive jobs may set this to true.
Definition Job.php:41
static newRootJobParams( $key)
Get "root job" parameters for a task.
Definition Job.php:296
getLastError()
string
Definition Job.php:432
static factory( $command, $params=[])
Create the appropriate object to handle a specific job.
Definition Job.php:61
array $metadata
Additional queue metadata.
Definition Job.php:35
__construct( $command, $params=null)
Definition Job.php:76
string $error
Text for error that occurred last.
Definition Job.php:44
JSON formatter wrapper class.
Service locator for MediaWiki core services.
static getInstance()
Returns the global default instance of the top level service locator.
Represents a title within MediaWiki.
Definition Title.php:69
Job that has a run() method and metadata accessors for JobQueue::pop() and JobQueue::ack().
Interface for objects (potentially) representing a page that can be viewable and linked to on a wiki.