Completed
Push — master ( 38797d...534d41 )
by Nate
03:48
created

AbstractQueue::run()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 50
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
dl 0
loc 50
ccs 0
cts 40
cp 0
rs 8.6315
c 0
b 0
f 0
cc 6
eloc 29
nc 6
nop 1
crap 42
1
<?php
2
3
/**
4
 * @author    Flipbox Factory
5
 * @copyright Copyright (c) 2017, Flipbox Digital
6
 * @link      https://github.com/flipbox/queue/releases/latest
7
 * @license   https://github.com/flipbox/queue/blob/master/LICENSE
8
 */
9
10
namespace flipbox\queue\queues;
11
12
use flipbox\queue\events\Queue as QueueEvent;
13
use flipbox\queue\events\QueueValue as QueueValueEvent;
14
use flipbox\queue\jobs\JobInterface;
15
use Yii;
16
use yii\base\Component;
17
use yii\base\Exception;
18
use yii\helpers\ArrayHelper;
19
use yii\helpers\Json;
20
21
/**
22
 * @author Flipbox Factory <[email protected]>
23
 * @since 1.0.0
24
 */
25
abstract class AbstractQueue extends Component implements QueueInterface
26
{
27
    /**
28
     * Event executed before a job is posted to the queue.
29
     */
30
    const EVENT_BEFORE_POST = 'beforePost';
31
32
    /**
33
     * Event executed before a job is posted to the queue.
34
     */
35
    const EVENT_AFTER_POST = 'afterPost';
36
37
    /**
38
     * Event executed before a job is being fetched from the queue.
39
     */
40
    const EVENT_BEFORE_FETCH = 'beforeFetch';
41
42
    /**
43
     * Event executed after a job is being fetched from the queue.
44
     */
45
    const EVENT_AFTER_FETCH = 'afterFetch';
46
47
    /**
48
     * Event executed before a job is being deleted from the queue.
49
     */
50
    const EVENT_BEFORE_DELETE = 'beforeDelete';
51
52
    /**
53
     * Event executed after a job is being deleted from the queue.
54
     */
55
    const EVENT_AFTER_DELETE = 'afterDelete';
56
57
    /**
58
     * Event executed before a job is being released from the queue.
59
     */
60
    const EVENT_BEFORE_RELEASE = 'beforeRelease';
61
62
    /**
63
     * Event executed after a job is being released from the queue.
64
     */
65
    const EVENT_AFTER_RELEASE = 'afterRelease';
66
67
    /**
68
     * Event executed before a job is being executed.
69
     */
70
    const EVENT_BEFORE_RUN = 'beforeRun';
71
72
    /**
73
     * Event executed after a job is being executed.
74
     */
75
    const EVENT_AFTER_RUN = 'afterRun';
76
77
    /**
78
     * This will release automatically on execution failure. i.e. when
79
     * the `run` method returns false or catch exception.
80
     *
81
     * @var bool
82
     */
83
    public $releaseOnFailure = true;
84
85
    /**
86
     * @inheritdoc
87
     */
88
    public function post(JobInterface $job): bool
89
    {
90
        $this->trigger(
91
            self::EVENT_BEFORE_POST,
92
            $beforeEvent = new QueueEvent(['job' => $job])
93
        );
94
95
        if (!$beforeEvent->isValid) {
96
            return false;
97
        }
98
99
        $return = $this->postJob($job);
100
        if (!$return) {
101
            return false;
102
        }
103
104
        $this->trigger(
105
            self::EVENT_AFTER_POST,
106
            new QueueEvent(['job' => $job])
107
        );
108
        return true;
109
    }
110
111
    /**
112
     * Post new job to the queue.  Override this for queue implementation.
113
     *
114
     * @param JobInterface $job
115
     * @return bool
116
     */
117
    abstract protected function postJob(JobInterface $job): bool;
118
119
    /**
120
     * @inheritdoc
121
     */
122
    public function fetch()
123
    {
124
        $this->trigger(self::EVENT_BEFORE_FETCH);
125
126
        $job = $this->fetchJob();
127
        if ($job == false) {
128
            return false;
129
        }
130
131
        $this->trigger(
132
            self::EVENT_AFTER_FETCH,
133
            new QueueEvent(['job' => $job])
134
        );
135
        return $job;
136
    }
137
138
    /**
139
     * Return next job from the queue. Override this for queue implementation.
140
     *
141
     * @return JobInterface|bool
142
     */
143
    abstract protected function fetchJob();
144
145
    /**
146
     * @inheritdoc
147
     */
148
    public function run(JobInterface $job)
149
    {
150
        $this->trigger(
151
            self::EVENT_BEFORE_RUN,
152
            $beforeEvent = new QueueEvent(['job' => $job])
153
        );
154
155
        if (!$beforeEvent->isValid) {
156
            return;
157
        }
158
159
        try {
160
            $value = $job->run();
161
        } catch (\Exception $e) {
162
            $class = get_class($job);
163
164
            Yii::error(
165
                "Fatal Error: Error running job '{$class}'. Id: {$job->getId()} Message: {$e->getMessage()}",
166
                'queue'
167
            );
168
169
            if ($this->releaseOnFailure) {
170
                $this->release($job);
171
            }
172
173
            throw new Exception(
174
                "Error running job '{$class}'. " .
175
                "Message: {$e->getMessage()}. " .
176
                "File: {$e->getFile()}[{$e->getLine()}]. Stack Trace: {$e->getTraceAsString()}",
177
                500
178
            );
179
        }
180
181
        $this->trigger(
182
            self::EVENT_AFTER_RUN,
183
            new QueueValueEvent(['job' => $job, 'value' => $value])
184
        );
185
186
        if ($value === false) {
187
            if ($this->releaseOnFailure) {
188
                $this->release($job);
189
            }
190
191
            return;
192
        }
193
194
        $this->delete($job);
195
196
        return;
197
    }
198
199
    /**
200
     * @inheritdoc
201
     */
202
    public function delete(JobInterface $job): bool
203
    {
204
        $this->trigger(
205
            self::EVENT_BEFORE_DELETE,
206
            $beforeEvent = new QueueEvent(['job' => $job])
207
        );
208
        if (!$beforeEvent->isValid) {
209
            return false;
210
        }
211
212
        $return = $this->deleteJob($job);
213
        if (!$return) {
214
            return false;
215
        }
216
217
        $this->trigger(
218
            self::EVENT_AFTER_DELETE,
219
            new QueueEvent(['job' => $job])
220
        );
221
        return true;
222
    }
223
224
    /**
225
     * Delete the job. Override this for the queue implementation.
226
     *
227
     * @param JobInterface $job
228
     * @return bool
229
     */
230
    abstract protected function deleteJob(JobInterface $job): bool;
231
232
    /**
233
     * @inheritdoc
234
     */
235
    public function release(JobInterface $job): bool
236
    {
237
        $this->trigger(
238
            self::EVENT_BEFORE_RELEASE,
239
            $beforeEvent = new QueueEvent(['job' => $job])
240
        );
241
        if (!$beforeEvent->isValid) {
242
            return false;
243
        }
244
245
        $return = $this->releaseJob($job);
246
        if (!$return) {
247
            return false;
248
        }
249
250
        $this->trigger(
251
            self::EVENT_AFTER_RELEASE,
252
            new QueueEvent(['job' => $job])
253
        );
254
        return true;
255
    }
256
257
    /**
258
     * Release the job. Override this for the queue implementation.
259
     *
260
     * @param JobInterface $job
261
     * @return bool
262
     */
263
    abstract protected function releaseJob(JobInterface $job): bool;
264
265
    /**
266
     * @param string $message
267
     * @return JobInterface
268
     * @throws Exception
269
     */
270
    protected function deserialize($message): JobInterface
271
    {
272
        // Deserialize
273
        $jobArray = Json::decode($message);
274
275
        // Create job
276
        $job = Yii::createObject($jobArray);
0 ignored issues
show
Documentation introduced by
$jobArray is of type *, but the function expects a callable.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
277
        if (!$job instanceof JobInterface) {
278
            throw new Exception('Invalid job');
279
        }
280
281
        return $job;
282
    }
283
284
    /**
285
     * @param JobInterface $job The job to serialize.
286
     * @return string JSON string.
287
     */
288
    protected function serialize(JobInterface $job)
289
    {
290
        $jobArray = ArrayHelper::toArray($job);
291
        $jobArray['class'] = get_class($job);
292
        return Json::encode($jobArray);
293
    }
294
}
295