Completed
Pull Request — master (#30)
by Matthew
23:29 queued 08:10
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 boolean $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
    /**
69
     * @param string $type
70
     * @param boolean $autoRetry
71
     */
72 17
    protected function updateJobMax(RetryableJob $job, $type, $maxStatus, $autoRetry)
73
    {
74 17
        $setMethod = 'set'.$type;
75 17
        $getMethod = 'get'.$type;
76 17
        $getMax = 'getMax'.$type;
77 17
        $job->$setMethod(intval($job->$getMethod()) + 1);
78 17
        if (!$this->updateMaxStatus($job, $maxStatus, $job->$getMax(), $job->$getMethod()) &&
79 17
            !$this->updateMaxStatus($job, RetryableJob::STATUS_MAX_RETRIES, $job->getMaxRetries(), $job->getRetries())) {
80 16
            if ($autoRetry) {
81 14
                return $this->resetRetryableJob($job);
82
            }
83
        }
84
85 17
        return false;
86
    }
87
88 9
    private function updateJobFailure(RetryableJob $job)
89
    {
90 9
        return $this->updateJobMax($job, 'Failures', RetryableJob::STATUS_MAX_FAILURES, $this->autoRetryOnFailure);
91
    }
92
93
    /**
94
     * Determine if we've hit a max retry condition.
95
     *
96
     * @param RetryableJob $job
97
     * @param int          $status
98
     * @param int|null     $max
99
     * @param int          $count
100
     *
101
     * @return bool
102
     */
103 19
    protected function updateMaxStatus(RetryableJob $job, $status, $max = null, $count = 0)
104
    {
105 19
        if (null !== $max && $count >= $max) {
106 17
            $job->setStatus($status);
107
108 17
            return true;
109
        }
110
111 18
        return false;
112
    }
113
114 14
    protected function resetRetryableJob(RetryableJob $job)
115
    {
116 14
        if ($this->resetJob($job)) {
117 14
            $this->getJobTimingManager()->recordTiming(JobTiming::STATUS_INSERT);
118
119 14
            return true;
120
        }
121
122
        return false;
123
    }
124
125
    /**
126
     * @param RetryableJob $job
127
     *
128
     * @return bool true if the job was successfully "reset", i.e. re-queued
129
     */
130
    abstract protected function resetJob(RetryableJob $job);
131
132 76
    protected function setBaseRetryableJobDefaults(RetryableJob $job)
133
    {
134 76
        if (null === $job->getMaxExceptions()) {
135 43
            $job->setMaxExceptions($this->defaultMaxExceptions);
136
        }
137
138 76
        if (null === $job->getMaxRetries()) {
139 43
            $job->setMaxRetries($this->defaultMaxRetries);
140
        }
141
142 76
        if (null === $job->getMaxFailures()) {
143 43
            $job->setMaxFailures($this->defaultMaxFailures);
144
        }
145
146 76
        if (null === $job->getCrcHash()) {
147 76
            $hashValues = array(get_class($job), $job->getMethod(), $job->getWorkerName(), $job->getArgs());
148 76
            $crcHash = hash('sha256', serialize($hashValues));
149 76
            $job->setCrcHash($crcHash);
150
        }
151 76
    }
152
153
    /**
154
     * @return int|null
155
     */
156 6
    public function getDefaultMaxRetries()
157
    {
158 6
        return $this->defaultMaxRetries;
159
    }
160
161
    /**
162
     * @param int|null $defaultMaxRetries
163
     */
164 6
    public function setDefaultMaxRetries($defaultMaxRetries)
165
    {
166 6
        $this->defaultMaxRetries = $defaultMaxRetries;
167 6
    }
168
169
    /**
170
     * @return int|null
171
     */
172 6
    public function getDefaultMaxFailures()
173
    {
174 6
        return $this->defaultMaxFailures;
175
    }
176
177
    /**
178
     * @param integer|null $defaultMaxFailures
179
     */
180 6
    public function setDefaultMaxFailures($defaultMaxFailures)
181
    {
182 6
        $this->defaultMaxFailures = $defaultMaxFailures;
183 6
    }
184
185
    /**
186
     * @return bool
187
     */
188 6
    public function getAutoRetryOnFailure()
189
    {
190 6
        return $this->autoRetryOnFailure;
191
    }
192
193
    /**
194
     * @param bool $autoRetryOnFailure
195
     */
196 18
    public function setAutoRetryOnFailure($autoRetryOnFailure)
197
    {
198 18
        $this->autoRetryOnFailure = $autoRetryOnFailure;
199 18
    }
200
201
    /**
202
     * @return bool
203
     */
204 6
    public function getAutoRetryOnException()
205
    {
206 6
        return $this->autoRetryOnException;
207
    }
208
209
    /**
210
     * @param bool $autoRetryOnException
211
     */
212 12
    public function setAutoRetryOnException($autoRetryOnException)
213
    {
214 12
        $this->autoRetryOnException = $autoRetryOnException;
215 12
    }
216
217
    /**
218
     * @return int|null
219
     */
220 6
    public function getDefaultMaxExceptions()
221
    {
222 6
        return $this->defaultMaxExceptions;
223
    }
224
225
    /**
226
     * @param integer|null $defaultMaxExceptions
227
     */
228 6
    public function setDefaultMaxExceptions($defaultMaxExceptions)
229
    {
230 6
        $this->defaultMaxExceptions = $defaultMaxExceptions;
231 6
    }
232
233 76
    protected function recordTiming(Job $job)
234
    {
235 76
        $status = JobTiming::STATUS_INSERT;
236 76
        if ($job->getWhenAt() && $job->getWhenAt() > (new \DateTime())) {
237 4
            $status = JobTiming::STATUS_INSERT_DELAYED;
238
        }
239
240 76
        $this->getJobTimingManager()->recordTiming($status);
241 76
    }
242
}
243