Test Failed
Pull Request — master (#56)
by
unknown
02:50
created

JobHandler::create()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 14
nc 6
nop 6
dl 0
loc 24
rs 9.4888
c 0
b 0
f 0
1
<?php
2
3
namespace Resque;
4
5
use \InvalidArgumentException;
6
use \Resque\Job\Status;
7
use \Resque\Exceptions\DoNotPerformException;
8
use \Resque\Job\FactoryInterface;
9
use \Resque\Job\Factory;
10
use \Error;
11
12
/**
13
 * Resque job.
14
 *
15
 * @package		Resque/JobHandler
16
 * @author		Chris Boulton <[email protected]>
17
 * @license		http://www.opensource.org/licenses/mit-license.php
18
 */
19
class JobHandler
20
{
21
	/**
22
	 * @var string The name of the queue that this job belongs to.
23
	 */
24
	public $queue;
25
26
	/**
27
	 * @var \Resque\Worker\Resque Instance of the Resque worker running this job.
28
	 */
29
	public $worker;
30
31
	/**
32
	 * @var array Array containing details of the job.
33
	 */
34
	public $payload;
35
36
	/**
37
	 * @var object|\Resque\Job\JobInterface Instance of the class performing work for this job.
38
	 */
39
	private $instance;
40
41
	/**
42
	 * @var \Resque\Job\FactoryInterface
43
	 */
44
	private $jobFactory;
45
46
	/**
47
	 * Instantiate a new instance of a job.
48
	 *
49
	 * @param string $queue The queue that the job belongs to.
50
	 * @param array $payload array containing details of the job.
51
	 */
52
	public function __construct($queue, $payload)
53
	{
54
		$this->queue = $queue;
55
		$this->payload = $payload;
56
	}
57
58
	/**
59
	 * Create a new job and save it to the specified queue.
60
	 *
61
	 * @param string $queue The name of the queue to place the job in.
62
	 * @param string $class The name of the class that contains the code to execute the job.
63
	 * @param array $args Any optional arguments that should be passed when the job is executed.
64
	 * @param boolean $monitor Set to true to be able to monitor the status of a job.
65
	 * @param string $id Unique identifier for tracking the job. Generated if not supplied.
66
	 * @param string $prefix The prefix needs to be set for the status key
67
	 *
68
	 * @return string
69
	 * @throws \InvalidArgumentException
70
	 */
71
	public static function create($queue, $class, $args = null, $monitor = false, $id = null, $prefix = "")
72
	{
73
		if (is_null($id)) {
74
			$id = Resque::generateJobId();
75
		}
76
77
		if ($args !== null && !is_array($args)) {
0 ignored issues
show
introduced by
The condition is_array($args) is always true.
Loading history...
78
			throw new InvalidArgumentException(
79
				'Supplied $args must be an array.'
80
			);
81
		}
82
		Resque::push($queue, array(
83
			'class'	     => $class,
84
			'args'	     => array($args),
85
			'id'	     => $id,
86
			'prefix'     => $prefix,
87
			'queue_time' => microtime(true),
88
		));
89
90
		if ($monitor) {
91
			Status::create($id, $prefix);
92
		}
93
94
		return $id;
95
	}
96
97
	/**
98
	 * Find the next available job from the specified queue and return an
99
	 * instance of JobHandler for it.
100
	 *
101
	 * @param string $queue The name of the queue to check for a job in.
102
	 * @return false|object Null when there aren't any waiting jobs, instance of Resque\JobHandler when a job was found.
103
	 */
104
	public static function reserve($queue)
105
	{
106
		$payload = Resque::pop($queue);
107
		if (!is_array($payload)) {
0 ignored issues
show
introduced by
The condition is_array($payload) is always true.
Loading history...
108
			return false;
109
		}
110
111
		return new JobHandler($queue, $payload);
112
	}
113
114
	/**
115
	 * Find the next available job from the specified queues using blocking list pop
116
	 * and return an instance of JobHandler for it.
117
	 *
118
	 * @param array             $queues
119
	 * @param int               $timeout
120
	 * @return false|object Null when there aren't any waiting jobs, instance of Resque\JobHandler when a job was found.
121
	 */
122
	public static function reserveBlocking(array $queues, $timeout = null)
123
	{
124
		$item = Resque::blpop($queues, $timeout);
125
126
		if (!is_array($item)) {
127
			return false;
128
		}
129
130
		return new JobHandler($item['queue'], $item['payload']);
131
	}
132
133
	/**
134
	 * Update the status of the current job.
135
	 *
136
	 * @param int $status Status constant from Resque\Job\Status indicating the current status of a job.
137
	 */
138
	public function updateStatus($status, $result = null)
139
	{
140
		if (empty($this->payload['id'])) {
141
			return;
142
		}
143
144
		$statusInstance = new Status($this->payload['id'], $this->getPrefix());
145
		$statusInstance->update($status, $result);
146
	}
147
148
	/**
149
	 * Return the status of the current job.
150
	 *
151
	 * @return int|null The status of the job as one of the Resque\Job\Status constants or null if job is not being tracked.
152
	 */
153
	public function getStatus()
154
	{
155
		if (empty($this->payload['id'])) {
156
			return null;
157
		}
158
159
		$status = new Status($this->payload['id'], $this->getPrefix());
160
		return $status->get();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $status->get() could also return false which is incompatible with the documented return type integer|null. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
161
	}
162
163
	/**
164
	 * Get the arguments supplied to this job.
165
	 *
166
	 * @return array Array of arguments.
167
	 */
168
	public function getArguments()
169
	{
170
		if (!isset($this->payload['args'])) {
171
			return array();
172
		}
173
174
		return $this->payload['args'][0];
175
	}
176
177
	/**
178
	 * Get the instantiated object for this job that will be performing work.
179
	 * @return \Resque\Job\JobInterface Instance of the object that this job belongs to.
180
	 * @throws \Resque\Exceptions\Exception
181
	 */
182
	public function getInstance()
183
	{
184
		if (!is_null($this->instance)) {
185
			return $this->instance;
186
		}
187
188
		$this->instance = $this->getJobFactory()->create($this->payload['class'], $this->getArguments(), $this->queue);
189
		$this->instance->job = $this;
190
		return $this->instance;
191
	}
192
193
	/**
194
	 * Actually execute a job by calling the perform method on the class
195
	 * associated with the job with the supplied arguments.
196
	 *
197
	 * @return bool
198
	 * @throws Resque\Exceptions\Exception When the job's class could not be found or it does not contain a perform method.
199
	 */
200
	public function perform()
201
	{
202
		$result = true;
203
		try {
204
			Event::trigger('beforePerform', $this);
205
206
			$instance = $this->getInstance();
207
			if (is_callable([$instance, 'setUp'])) {
208
				$instance->setUp();
0 ignored issues
show
Bug introduced by
The method setUp() does not exist on Resque\Job\JobInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

208
				$instance->/** @scrutinizer ignore-call */ 
209
               setUp();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
209
			}
210
211
			$result = $instance->perform();
212
213
			if (is_callable([$instance, 'tearDown'])) {
214
				$instance->tearDown();
0 ignored issues
show
Bug introduced by
The method tearDown() does not exist on Resque\Job\JobInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

214
				$instance->/** @scrutinizer ignore-call */ 
215
               tearDown();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
215
			}
216
217
			Event::trigger('afterPerform', $this);
218
		}
219
		// beforePerform/setUp have said don't perform this job. Return.
220
		catch (DoNotPerformException $e) {
221
			$result = false;
222
		}
223
224
		return $result;
225
	}
226
227
	/**
228
	 * Mark the current job as having failed.
229
	 *
230
	 * @param $exception
231
	 */
232
	public function fail($exception)
233
	{
234
		Event::trigger('onFailure', array(
235
			'exception' => $exception,
236
			'job' => $this,
237
		));
238
239
		$this->updateStatus(Status::STATUS_FAILED);
240
		if ($exception instanceof Error) {
241
			FailureHandler::createFromError(
242
				$this->payload,
243
				$exception,
244
				$this->worker,
245
				$this->queue
246
			);
247
		} else {
248
			FailureHandler::create(
249
				$this->payload,
250
				$exception,
251
				$this->worker,
252
				$this->queue
253
			);
254
		}
255
		Stat::incr('failed');
256
		Stat::incr('failed:' . $this->worker);
257
	}
258
259
	/**
260
	 * Re-queue the current job.
261
	 * @return string
262
	 */
263
	public function recreate()
264
	{
265
		$monitor = false;
266
		if (!empty($this->payload['id'])) {
267
			$status = new Status($this->payload['id'], $this->getPrefix());
268
			if ($status->isTracking()) {
269
				$monitor = true;
270
			}
271
		}
272
273
		return self::create($this->queue, $this->payload['class'], $this->getArguments(), $monitor, null, $this->getPrefix());
274
	}
275
276
	/**
277
	 * Generate a string representation used to describe the current job.
278
	 *
279
	 * @return string The string representation of the job.
280
	 */
281
	public function __toString()
282
	{
283
		$name = array(
284
			'Job{' . $this->queue . '}'
285
		);
286
		if (!empty($this->payload['id'])) {
287
			$name[] = 'ID: ' . $this->payload['id'];
288
		}
289
		$name[] = $this->payload['class'];
290
		if (!empty($this->payload['args'])) {
291
			$name[] = json_encode($this->payload['args']);
292
		}
293
		return '(' . implode(' | ', $name) . ')';
294
	}
295
296
	/**
297
	 * @param Resque\Job\FactoryInterface $jobFactory
0 ignored issues
show
Bug introduced by
The type Resque\Resque\Job\FactoryInterface was not found. Did you mean Resque\Job\FactoryInterface? If so, make sure to prefix the type with \.
Loading history...
298
	 * @return Resque\JobHandler
0 ignored issues
show
Bug introduced by
The type Resque\Resque\JobHandler was not found. Did you mean Resque\JobHandler? If so, make sure to prefix the type with \.
Loading history...
299
	 */
300
	public function setJobFactory(FactoryInterface $jobFactory)
301
	{
302
		$this->jobFactory = $jobFactory;
303
304
		return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type Resque\JobHandler which is incompatible with the documented return type Resque\Resque\JobHandler.
Loading history...
305
	}
306
307
	/**
308
	 * @return Resque\Job\FactoryInterface
309
	 */
310
	public function getJobFactory()
311
	{
312
		if ($this->jobFactory === null) {
313
			$this->jobFactory = new Factory();
314
		}
315
		return $this->jobFactory;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->jobFactory returns the type Resque\Job\Factory|Resque\Job\FactoryInterface which is incompatible with the documented return type Resque\Resque\Job\FactoryInterface.
Loading history...
316
	}
317
318
	/**
319
	 * @return string
320
	 */
321
	private function getPrefix()
322
	{
323
		if (isset($this->payload['prefix'])) {
324
			return $this->payload['prefix'];
325
		}
326
327
		return '';
328
	}
329
}
330