Issues (25)

src/Ganesha/Strategy/Count.php (3 issues)

Labels
Severity
1
<?php
2
namespace Ackintosh\Ganesha\Strategy;
3
4
use Ackintosh\Ganesha;
5
use Ackintosh\Ganesha\Configuration;
6
use Ackintosh\Ganesha\Exception\StorageException;
7
use Ackintosh\Ganesha\Storage;
8
use Ackintosh\Ganesha\StrategyInterface;
9
use InvalidArgumentException;
10
use LogicException;
11
12
class Count implements StrategyInterface
13
{
14
    /**
15
     * @var Configuration
16
     */
17
    private $configuration;
18
19
    /**
20
     * @var Storage
21
     */
22
    private $storage;
23
24
    /**
25
     * @var array
26
     */
27
    private static $requirements = [
28
        'adapter',
29
        'failureCountThreshold',
30
        'intervalToHalfOpen',
31
    ];
32
33
    /**
34
     * @param Configuration $configuration
35
     * @param Storage $storage
36
     */
37
    private function __construct(Configuration $configuration, Storage $storage)
38
    {
39
        $this->configuration = $configuration;
40
        $this->storage = $storage;
41
    }
42
43
    /**
44
     * @param array $params
45
     * @throws LogicException
46
     */
47
    public static function validate(array $params): void
48
    {
49
        foreach (self::$requirements as $r) {
50
            if (!isset($params[$r])) {
51
                throw new LogicException($r . ' is required');
52
            }
53
        }
54
55
        if (!call_user_func([$params['adapter'], 'supportCountStrategy'])) {
56
            throw new InvalidArgumentException(get_class($params['adapter'])  . " doesn't support Count Strategy.");
57
        }
58
    }
59
60
    /**
61
     * @param Configuration $configuration
62
     * @return Count
63
     */
64
    public static function create(Configuration $configuration): StrategyInterface
65
    {
66
        return new self(
67
            $configuration,
68
            new Storage(
69
                $configuration['adapter'],
0 ignored issues
show
It seems like $configuration['adapter'] can also be of type null; however, parameter $adapter of Ackintosh\Ganesha\Storage::__construct() does only seem to accept Ackintosh\Ganesha\Storage\AdapterInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

69
                /** @scrutinizer ignore-type */ $configuration['adapter'],
Loading history...
70
                $configuration['storageKeys'],
0 ignored issues
show
It seems like $configuration['storageKeys'] can also be of type null; however, parameter $storageKeys of Ackintosh\Ganesha\Storage::__construct() does only seem to accept Ackintosh\Ganesha\Storage\StorageKeysInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

70
                /** @scrutinizer ignore-type */ $configuration['storageKeys'],
Loading history...
71
                null
72
            )
73
        );
74
    }
75
76
    /**
77
     * @param string $service
78
     * @return int
79
     */
80
    public function recordFailure(string $service): int
81
    {
82
        $this->storage->setLastFailureTime($service, time());
83
        $this->storage->incrementFailureCount($service);
84
85
        if ($this->storage->getFailureCount($service) >= $this->configuration['failureCountThreshold']
86
            && $this->storage->getStatus($service) === Ganesha::STATUS_CALMED_DOWN
87
        ) {
88
            $this->storage->setStatus($service, Ganesha::STATUS_TRIPPED);
89
            return Ganesha::STATUS_TRIPPED;
90
        }
91
92
        return Ganesha::STATUS_CALMED_DOWN;
93
    }
94
95
    /**
96
     * @param string $service
97
     * @return int
98
     */
99
    public function recordSuccess(string $service): ?int
100
    {
101
        $this->storage->decrementFailureCount($service);
102
103
        $status = $this->storage->getStatus($service);
104
        if ($this->storage->getFailureCount($service) === 0
105
            && $status === Ganesha::STATUS_TRIPPED
106
        ) {
107
            $this->storage->setStatus($service, Ganesha::STATUS_CALMED_DOWN);
108
            return Ganesha::STATUS_CALMED_DOWN;
109
        }
110
111
        return null;
112
    }
113
114
    /**
115
     * @return void
116
     */
117
    public function reset(): void
118
    {
119
        $this->storage->reset();
120
    }
121
122
    /**
123
     * @param string $service
124
     * @return bool
125
     */
126
    public function isAvailable(string $service): bool
127
    {
128
        return $this->isClosed($service) || $this->isHalfOpen($service);
129
    }
130
131
    /**
132
     * @param string $service
133
     * @return bool
134
     * @throws StorageException
135
     */
136
    private function isClosed(string $service): bool
137
    {
138
        return $this->storage->getFailureCount($service) < $this->configuration['failureCountThreshold'];
139
    }
140
141
    /**
142
     * @param string $service
143
     * @return bool
144
     * @throws StorageException
145
     */
146
    private function isHalfOpen(string $service): bool
147
    {
148
        if (is_null($lastFailureTime = $this->storage->getLastFailureTime($service))) {
149
            return false;
150
        }
151
152
        if ((time() - $lastFailureTime) > $this->configuration['intervalToHalfOpen']) {
153
            $this->storage->setFailureCount($service, $this->configuration['failureCountThreshold']);
0 ignored issues
show
It seems like $this->configuration['failureCountThreshold'] can also be of type null; however, parameter $failureCount of Ackintosh\Ganesha\Storage::setFailureCount() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

153
            $this->storage->setFailureCount($service, /** @scrutinizer ignore-type */ $this->configuration['failureCountThreshold']);
Loading history...
154
            $this->storage->setLastFailureTime($service, time());
155
            return true;
156
        }
157
158
        return false;
159
    }
160
}
161