RetryOnFailureInterceptor::invoke()   B
last analyzed

Complexity

Conditions 6
Paths 18

Size

Total Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 34
rs 8.7537
c 0
b 0
f 0
cc 6
nc 18
nop 1
1
<?php
2
declare(strict_types=1);
3
4
/**
5
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
7
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
8
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
9
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
10
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
11
 * THE SOFTWARE.
12
 *
13
 * This software consists of voluntary contributions made by many individuals
14
 * and is licensed under the MIT license.
15
 *
16
 * Copyright (c) 2015-2020 Yuuki Takezawa
17
 *
18
 */
19
20
namespace Ytake\LaravelAspect\Interceptor;
21
22
use Ray\Aop\MethodInvocation;
23
use Ray\Aop\MethodInterceptor;
24
use Ytake\LaravelAspect\Annotation\RetryOnFailure;
25
use Ytake\LaravelAspect\Annotation\AnnotationReaderTrait;
26
27
use function ltrim;
28
use function get_class;
29
use function sleep;
30
31
/**
32
 * Class RetryOnFailureInterceptor
33
 */
34
final class RetryOnFailureInterceptor implements MethodInterceptor
35
{
36
    use AnnotationReaderTrait;
37
38
    /** @var array|null */
39
    private static $attempt = null;
40
41
    /**
42
     * @param MethodInvocation $invocation
43
     *
44
     * @return object
45
     * @throws \Exception
46
     */
47
    public function invoke(MethodInvocation $invocation)
48
    {
49
        /** @var RetryOnFailure $annotation */
50
        $annotation = $invocation->getMethod()->getAnnotation($this->annotation) ?? new $this->annotation([]);
51
        $key = $this->keyName($invocation);
52
53
        if (isset(self::$attempt[$key]) === false) {
54
            self::$attempt[$key] = $annotation->attempts;
55
        }
56
57
        try {
58
            self::$attempt[$key]--;
59
60
            return $invocation->proceed();
61
        } catch (\Exception $e) {
62
            if (ltrim($annotation->ignore, '\\') === get_class($e)) {
63
                self::$attempt[$key] = null;
64
                throw $e;
65
            }
66
67
            $pass = array_filter($annotation->types, function ($values) use ($e) {
68
                return ltrim($values, '\\') === get_class($e);
69
            });
70
            if ($pass !== false) {
71
                if (self::$attempt[$key] > 0) {
72
                    sleep($annotation->delay);
73
74
                    return $invocation->proceed();
75
                }
76
            }
77
            self::$attempt[$key] = null;
78
            throw $e;
79
        }
80
    }
81
82
    /**
83
     * @param MethodInvocation $invocation
84
     *
85
     * @return string
86
     */
87
    protected function keyName(MethodInvocation $invocation): string
88
    {
89
        return $invocation->getMethod()->class . "$" . $invocation->getMethod()->getName();
0 ignored issues
show
Bug introduced by
Consider using $invocation->getMethod()->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
90
    }
91
}
92