Storage::setSuccess()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 5
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 7
rs 10
1
<?php
2
3
/**
4
 * This file is part of the bugloos/fault-tolerance-bundle project.
5
 * (c) Bugloos <https://bugloos.com/>
6
 * For the full copyright and license information, please view
7
 * the LICENSE file that was distributed with this source code.
8
 *
9
 * @author Mojtaba Gheytasi <[email protected]>
10
 */
11
12
namespace Bugloos\FaultToleranceBundle\CircuitBreaker\Storage;
13
14
use Psr\Cache\InvalidArgumentException;
15
use Symfony\Component\Cache\Adapter\AdapterInterface;
16
17
class Storage
18
{
19
    private AdapterInterface $adapter;
20
21
    public function __construct(AdapterInterface $adapter)
22
    {
23
        $this->adapter = $adapter;
24
    }
25
26
    /**
27
     * @throws InvalidArgumentException
28
     */
29
    public function isOpen(string $commandKey): bool
30
    {
31
        return (bool) $this->adapter->getItem($this->openCacheKey($commandKey))->get();
32
    }
33
34
    /**
35
     * @throws InvalidArgumentException
36
     */
37
    public function isHalfOpen(string $commandKey): bool
38
    {
39
        return (bool) $this->adapter->getItem($this->halfOpenCacheKey($commandKey))->get();
40
    }
41
42
    /**
43
     * @throws InvalidArgumentException
44
     */
45
    public function setOpenCircuit(string $commandKey, int $timeWindow): void
46
    {
47
        $openCircuit = $this->adapter->getItem($this->openCacheKey($commandKey));
48
        $openCircuit
49
            ->set(true)
50
            ->expiresAfter($timeWindow);
51
52
        $this->adapter->save($openCircuit);
53
    }
54
55
    /**
56
     * @throws InvalidArgumentException
57
     */
58
    public function setHalfOpenCircuit(string $commandKey, int $timeWindow, int $intervalToHalfOpen): void
59
    {
60
        $halfOpenCircuit = $this->adapter->getItem($this->halfOpenCacheKey($commandKey));
61
        $halfOpenCircuit
62
            ->set(true)
63
            ->expiresAfter($timeWindow + $intervalToHalfOpen);
64
65
        $this->adapter->save($halfOpenCircuit);
66
    }
67
68
    /**
69
     * @throws InvalidArgumentException
70
     */
71
    public function incrementFailure(string $commandKey, int $timeWindow): void
72
    {
73
        $failures = $this->adapter->getItem($this->failuresCacheKey($commandKey));
74
75
        if ($failures->get()) {
76
            $failuresExpireDatetime = $this->getFailuresExpireTime($commandKey);
77
78
            $failures->set($failures->get() + 1)
79
                ->expiresAt($failuresExpireDatetime);
80
        } else {
81
            $expirationDatetime = $this->makeFailuresExpireTime($timeWindow);
82
83
            $failures->set(1)
84
                ->expiresAt($expirationDatetime);
85
86
            $this->rememberFailuresExpireTime($commandKey, $expirationDatetime);
87
        }
88
89
        $this->adapter->save($failures);
90
    }
91
92
    /**
93
     * @throws InvalidArgumentException
94
     */
95
    public function failureCount(string $commandKey): int
96
    {
97
        return $this->adapter->getItem($this->failuresCacheKey($commandKey))->get() ?? 0;
98
    }
99
100
    /**
101
     * @throws InvalidArgumentException
102
     */
103
    public function setSuccess(string $commandKey): void
104
    {
105
        $this->adapter->deleteItems([
106
            $this->halfOpenCacheKey($commandKey),
107
            $this->openCacheKey($commandKey),
108
            $this->failuresCacheKey($commandKey),
109
            $this->failuresExpireTimeCacheKey($commandKey),
110
        ]);
111
    }
112
113
    private function failuresCacheKey(string $commandKey): string
114
    {
115
        return $commandKey . '.failures';
116
    }
117
118
    private function openCacheKey(string $commandKey): string
119
    {
120
        return $commandKey . '.open';
121
    }
122
123
    private function halfOpenCacheKey(string $commandKey): string
124
    {
125
        return $commandKey . '.halfOpen';
126
    }
127
128
    private function failuresExpireTimeCacheKey(string $commandKey): string
129
    {
130
        return $this->failuresCacheKey($commandKey) . '.expireTime';
131
    }
132
133
    /**
134
     * @throws InvalidArgumentException
135
     */
136
    private function getFailuresExpireTime(string $commandKey): \DateTime
137
    {
138
        return $this->adapter->getItem(
139
            $this->failuresExpireTimeCacheKey($commandKey)
140
        )->get();
141
    }
142
143
    /**
144
     * @throws InvalidArgumentException
145
     */
146
    private function rememberFailuresExpireTime(string $commandKey, \DateTime $expirationDatetime)
147
    {
148
        $failuresExpireDatetime = $this->adapter->getItem(
149
            $this->failuresExpireTimeCacheKey($commandKey)
150
        )
151
            ->set($expirationDatetime)
152
            ->expiresAt($expirationDatetime);
153
154
        $this->adapter->save($failuresExpireDatetime);
155
    }
156
157
    private function makeFailuresExpireTime(int $timeWindow): \DateTime
158
    {
159
        return (new \DateTime())
160
            ->add(
161
                date_interval_create_from_date_string("$timeWindow seconds")
162
            );
163
    }
164
}
165