Completed
Pull Request — master (#30)
by Matthew
14:29
created

RetryableJobManager::save()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 14
ccs 8
cts 8
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 8
nc 3
nop 1
crap 3
1
<?php
2
3
namespace Dtc\QueueBundle\Manager;
4
5
use Dtc\QueueBundle\Model\BaseJob;
6
use Dtc\QueueBundle\Model\RetryableJob;
7
use Dtc\QueueBundle\Model\Job;
8
use Dtc\QueueBundle\Model\JobTiming;
9
10
abstract class RetryableJobManager extends AbstractJobManager
11
{
12
    protected $defaultMaxRetries;
13
    protected $defaultMaxFailures;
14
    protected $defaultMaxExceptions;
15
16
    protected $autoRetryOnFailure;
17
    protected $autoRetryOnException;
18
19
    abstract protected function retryableSave(RetryableJob $job);
20
21
    /**
22
     * @param RetryableJob $job
23
     * @param $retry bool
24
     *
25
     * @return
26
     */
27
    abstract protected function retryableSaveHistory(RetryableJob $job, $retry);
28
29 76
    public function save(Job $job)
30
    {
31 76
        if (!$job instanceof RetryableJob) {
32 3
            throw new \InvalidArgumentException('Job is not instanceof '.RetryableJob::class);
33
        }
34
35 76
        if (!$job->getId()) {
36 76
            $this->setBaseRetryableJobDefaults($job);
37
        }
38 76
        $this->recordTiming($job);
39 76
        $job->setUpdatedAt(new \DateTime());
40
41 76
        return $this->retryableSave($job);
42
    }
43
44
    /**
45
     * @return bool true if retry
46
     */
47 20
    public function saveHistory(Job $job)
48
    {
49 20
        if (!$job instanceof RetryableJob) {
50 3
            throw new \InvalidArgumentException('job not instance of '.RetryableJob::class);
51
        }
52
53 20
        switch ($job->getStatus()) {
54 20
            case BaseJob::STATUS_FAILURE:
55 9
                return $this->retryableSaveHistory($job, $this->updateJobFailure($job));
56 11
            case BaseJob::STATUS_EXCEPTION:
57 6
                return $this->retryableSaveHistory($job, $this->updateJobException($job));
58
        }
59
60 5
        return $this->retryableSaveHistory($job, false);
61
    }
62
63 6
    private function updateJobException(RetryableJob $job)
64
    {
65 6
        return $this->updateJobMax($job, 'Exceptions', RetryableJob::STATUS_MAX_EXCEPTIONS, $this->autoRetryOnException);
66
    }
67
68 17
    protected function updateJobMax(RetryableJob $job, $type, $maxStatus, $autoRetry)
69
    {
70 17
        $setMethod = 'set'.$type;
71 17
        $getMethod = 'get'.$type;
72 17
        $getMax = 'getMax'.$type;
73 17
        $job->$setMethod(intval($job->$getMethod()) + 1);
74 17
        if (!$this->updateMaxStatus($job, $maxStatus, $job->$getMax(), $job->$getMethod()) &&
75 17
            !$this->updateMaxStatus($job, RetryableJob::STATUS_MAX_RETRIES, $job->getMaxRetries(), $job->getRetries())) {
76 16
            if ($autoRetry) {
77 14
                return $this->resetRetryableJob($job);
78
            }
79
        }
80
81 17
        return false;
82
    }
83
84 9
    private function updateJobFailure(RetryableJob $job)
85
    {
86 9
        return $this->updateJobMax($job, 'Failures', RetryableJob::STATUS_MAX_FAILURES, $this->autoRetryOnFailure);
87
    }
88
89
    /**
90
     * Determine if we've hit a max retry condition.
91
     *
92
     * @param RetryableJob $job
93
     * @param int          $status
94
     * @param int|null     $max
95
     * @param int          $count
96
     *
97
     * @return bool
98
     */
99 19
    protected function updateMaxStatus(RetryableJob $job, $status, $max = null, $count = 0)
100
    {
101 19
        if (null !== $max && $count >= $max) {
102 17
            $job->setStatus($status);
103
104 17
            return true;
105
        }
106
107 18
        return false;
108
    }
109
110 14
    protected function resetRetryableJob(RetryableJob $job)
111
    {
112 14
        if ($this->resetJob($job)) {
113 14
            $this->getJobTimingManager()->recordTiming(JobTiming::STATUS_INSERT);
114
115 14
            return true;
116
        }
117
118
        return false;
119
    }
120
121
    /**
122
     * @param RetryableJob $job
123
     *
124
     * @return bool true if the job was successfully "reset", i.e. re-queued
125
     */
126
    abstract protected function resetJob(RetryableJob $job);
127
128 76
    protected function setBaseRetryableJobDefaults(RetryableJob $job)
129
    {
130 76
        if (null === $job->getMaxExceptions()) {
131 43
            $job->setMaxExceptions($this->defaultMaxExceptions);
132
        }
133
134 76
        if (null === $job->getMaxRetries()) {
135 43
            $job->setMaxRetries($this->defaultMaxRetries);
136
        }
137
138 76
        if (null === $job->getMaxFailures()) {
139 43
            $job->setMaxFailures($this->defaultMaxFailures);
140
        }
141
142 76
        if (null === $job->getCrcHash()) {
143 76
            $hashValues = array(get_class($job), $job->getMethod(), $job->getWorkerName(), $job->getArgs());
144 76
            $crcHash = hash('sha256', serialize($hashValues));
145 76
            $job->setCrcHash($crcHash);
146
        }
147 76
    }
148
149
    /**
150
     * @return int|null
151
     */
152 6
    public function getDefaultMaxRetries()
153
    {
154 6
        return $this->defaultMaxRetries;
155
    }
156
157
    /**
158
     * @param int|null $defaultMaxRetries
159
     */
160 6
    public function setDefaultMaxRetries($defaultMaxRetries)
161
    {
162 6
        $this->defaultMaxRetries = $defaultMaxRetries;
163 6
    }
164
165
    /**
166
     * @return int|null
167
     */
168 6
    public function getDefaultMaxFailures()
169
    {
170 6
        return $this->defaultMaxFailures;
171
    }
172
173
    /**
174
     * @param int|null $defaultMaxFailure
0 ignored issues
show
Documentation introduced by
There is no parameter named $defaultMaxFailure. Did you maybe mean $defaultMaxFailures?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
175
     */
176 6
    public function setDefaultMaxFailures($defaultMaxFailures)
177
    {
178 6
        $this->defaultMaxFailures = $defaultMaxFailures;
179 6
    }
180
181
    /**
182
     * @return bool
183
     */
184 6
    public function getAutoRetryOnFailure()
185
    {
186 6
        return $this->autoRetryOnFailure;
187
    }
188
189
    /**
190
     * @param bool $autoRetryOnFailure
191
     */
192 18
    public function setAutoRetryOnFailure($autoRetryOnFailure)
193
    {
194 18
        $this->autoRetryOnFailure = $autoRetryOnFailure;
195 18
    }
196
197
    /**
198
     * @return bool
199
     */
200 6
    public function getAutoRetryOnException()
201
    {
202 6
        return $this->autoRetryOnException;
203
    }
204
205
    /**
206
     * @param bool $autoRetryOnException
207
     */
208 12
    public function setAutoRetryOnException($autoRetryOnException)
209
    {
210 12
        $this->autoRetryOnException = $autoRetryOnException;
211 12
    }
212
213
    /**
214
     * @return int|null
215
     */
216 6
    public function getDefaultMaxExceptions()
217
    {
218 6
        return $this->defaultMaxExceptions;
219
    }
220
221
    /**
222
     * @param int|null $defaultMaxException
0 ignored issues
show
Documentation introduced by
There is no parameter named $defaultMaxException. Did you maybe mean $defaultMaxExceptions?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
223
     */
224 6
    public function setDefaultMaxExceptions($defaultMaxExceptions)
225
    {
226 6
        $this->defaultMaxExceptions = $defaultMaxExceptions;
227 6
    }
228
229 76
    protected function recordTiming(Job $job)
230
    {
231 76
        $status = JobTiming::STATUS_INSERT;
232 76
        if ($job->getWhenAt() && $job->getWhenAt() > (new \DateTime())) {
233 4
            $status = JobTiming::STATUS_INSERT_DELAYED;
234
        }
235
236 76
        $this->getJobTimingManager()->recordTiming($status);
237 76
    }
238
}
239