SwooleTableAdapter::checkExtensionLoaded()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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