RedisAdapter::setSuccess()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 6
c 3
b 0
f 0
dl 0
loc 9
rs 10
cc 1
nc 1
nop 1
1
<?php declare(strict_types=1);
2
3
namespace LeoCarmo\CircuitBreaker\Adapters;
4
5
class RedisAdapter implements AdapterInterface
6
{
7
    /**
8
     * @var \Redis
9
     */
10
    protected $redis;
11
12
    /**
13
     * @var string
14
     */
15
    protected string $redisNamespace;
16
17
    /**
18
     * Set settings for start circuit service
19
     *
20
     * @param $redis
21
     * @param string $redisNamespace
22
     */
23
    public function __construct($redis, string $redisNamespace)
24
    {
25
        $this->checkExtensionLoaded();
26
        $this->redis = $redis;
27
        $this->redisNamespace = $redisNamespace;
28
    }
29
30
    protected function checkExtensionLoaded()
31
    {
32
        if (! extension_loaded('redis')) {
33
            throw new \RuntimeException('Extension redis is required to use RedisAdapter.');
34
        }
35
    }
36
37
    /**
38
     * @param string $service
39
     * @return bool
40
     */
41
    public function isOpen(string $service): bool
42
    {
43
        return (bool) $this->redis->get(
44
            $this->makeNamespace($service) . ':open'
45
        );
46
    }
47
48
    /**
49
     * @param string $service
50
     * @param int $failureRateThreshold
51
     * @return bool
52
     */
53
    public function reachRateLimit(string $service, int $failureRateThreshold): bool
54
    {
55
        $failures = (int) $this->redis->get(
56
            $this->makeNamespace($service) . ':failures'
57
        );
58
59
        return ($failures >= $failureRateThreshold);
60
    }
61
62
    /**
63
     * @param string $service
64
     * @return bool|string
65
     */
66
    public function isHalfOpen(string $service): bool
67
    {
68
        return (bool) $this->redis->get(
69
            $this->makeNamespace($service) . ':half_open'
70
        );
71
    }
72
73
    /**
74
     * @param string $service
75
     * @param int $timeWindow
76
     * @return bool
77
     */
78
    public function incrementFailure(string $service, int $timeWindow) : bool
79
    {
80
        $serviceName = $this->makeNamespace($service) . ':failures';
81
82
        if (! $this->redis->get($serviceName)) {
83
            $this->redis->multi();
84
            $this->redis->incr($serviceName);
85
            $this->redis->expire($serviceName, $timeWindow);
86
            return (bool) ($this->redis->exec()[0] ?? false);
87
        }
88
89
        return (bool) $this->redis->incr($serviceName);
90
    }
91
92
    /**
93
     * @param string $service
94
     */
95
    public function setSuccess(string $service): void
96
    {
97
        $serviceName = $this->makeNamespace($service);
98
99
        $this->redis->multi();
100
        $this->redis->del($serviceName . ':open');
101
        $this->redis->del($serviceName . ':failures');
102
        $this->redis->del($serviceName . ':half_open');
103
        $this->redis->exec();
104
    }
105
106
    /**
107
     * @param string $service
108
     * @param int $timeWindow
109
     */
110
    public function setOpenCircuit(string $service, int $timeWindow): void
111
    {
112
        $this->redis->set(
113
            $this->makeNamespace($service) . ':open',
114
            time(),
115
            $timeWindow
116
        );
117
    }
118
119
    /**
120
     * @param string $service
121
     * @param int $timeWindow
122
     * @param int $intervalToHalfOpen
123
     */
124
    public function setHalfOpenCircuit(string $service, int $timeWindow, int $intervalToHalfOpen): void
125
    {
126
        $this->redis->set(
127
            $this->makeNamespace($service) . ':half_open',
128
            time(),
129
            ($timeWindow + $intervalToHalfOpen)
130
        );
131
    }
132
133
    public function getFailuresCounter(string $service): int
134
    {
135
        $failures = $this->redis->get(
136
            $this->makeNamespace($service) . ':failures'
137
        );
138
139
        return (int) $failures;
140
    }
141
142
    /**
143
     * @param string $service
144
     * @return string
145
     */
146
    protected function makeNamespace(string $service): string
147
    {
148
        return 'circuit-breaker:' . $this->redisNamespace . ':' . $service;
149
    }
150
}
151