Cerberus   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 135
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 6
Bugs 3 Features 1
Metric Value
wmc 11
c 6
b 3
f 1
lcom 1
cbo 2
dl 0
loc 135
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A isAvailable() 0 4 1
A __construct() 0 7 1
B getStatus() 0 38 5
A reportFailure() 0 5 1
A reportSuccess() 0 5 1
A setNamespace() 0 8 2
1
<?php
2
3
/**
4
 * The Cerberus class.
5
 *
6
 * @author  Leandro Silva <[email protected]>
7
 * @license https://github.com/mt-olympus/cerberus/blob/master/LICENSE MIT Licence
8
 */
9
namespace Cerberus;
10
11
use Zend\Cache\Storage\StorageInterface;
12
13
/**
14
 * The Cerberus Class.
15
 *
16
 * @author  Leandro Silva <[email protected]>
17
 * @license https://github.com/mt-olympus/cerberus/blob/master/LICENSE MIT Licence
18
 */
19
class Cerberus implements CerberusInterface
20
{
21
    /**
22
     * The storage object.
23
     *
24
     * @var \Zend\Cache\Storage\StorageInterface
25
     */
26
    private $storage;
27
28
    /**
29
     * Maximum number of failures to open the circuit.
30
     *
31
     * @var int
32
     */
33
    private $maxFailures;
34
35
    /**
36
     * Number of seconds to change from OPEN to HALF OPEN and try the connection again.
37
     *
38
     * @var int
39
     */
40
    private $timeout;
41
42
    /**
43
     * The default namespace used by the zend-cache storage.
44
     *
45
     * @var string
46
     */
47
    private $defaultNamespace;
48
49
    /**
50
     * Constructor.
51
     *
52
     * @param StorageInterface $storage     The storage object
53
     * @param int              $maxFailures Maximum number of failures to open the circuit
54
     * @param int              $timeout     Number of seconds to change from OPEN to HALF OPEN
55
     */
56
    public function __construct(StorageInterface $storage, $maxFailures = 5, $timeout = 30)
57
    {
58
        $this->maxFailures = (int) $maxFailures;
59
        $this->timeout = (int) $timeout;
60
        $this->storage = $storage;
61
        $this->defaultNamespace = $this->storage->getOptions()->getNamespace();
62
    }
63
64
    /**
65
     * {@inheritdoc}
66
     *
67
     * @see \Cerberus\CerberusInterface::isAvailable()
68
     */
69
    public function isAvailable($serviceName = null)
70
    {
71
        return $this->getStatus($serviceName) !== CerberusInterface::OPEN;
72
    }
73
74
    /**
75
     * {@inheritdoc}
76
     *
77
     * @see \Cerberus\CerberusInterface::getStatus()
78
     */
79
    public function getStatus($serviceName = null)
80
    {
81
        $this->setNamespace($serviceName);
82
83
        $success = false;
84
        $failures = (int) $this->storage->getItem('failures', $success);
85
        if (!$success) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $success of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
86
            $failures = 0;
87
            $this->storage->setItem('failures', $failures);
88
        }
89
90
        // Still has failures left
91
        if ($failures < $this->maxFailures) {
92
            return CerberusInterface::CLOSED;
93
        }
94
95
        $success = false;
96
        $lastAttempt = $this->storage->getItem('last_attempt', $success);
97
98
        // This is the first attempt after a failure, open the circuit
99
        if (!$success) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $success of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
100
            $lastAttempt = time();
101
            $this->storage->setItem('last_attempt', $lastAttempt);
102
103
            return CerberusInterface::OPEN;
104
        }
105
106
        // Reached maxFailues but has passed the timeout limit, so we can try again
107
        // We update the lastAttempt so only one call passes through
108
        if (time() - $lastAttempt >= $this->timeout) {
109
            $lastAttempt = time();
110
            $this->storage->setItem('last_attempt', $lastAttempt);
111
112
            return CerberusInterface::HALF_OPEN;
113
        }
114
115
        return CerberusInterface::OPEN;
116
    }
117
118
    /**
119
     * {@inheritdoc}
120
     *
121
     * @see \Cerberus\CerberusInterface::reportFailure()
122
     */
123
    public function reportFailure($serviceName = null)
124
    {
125
        $this->setNamespace($serviceName);
126
        $this->storage->incrementItem('failures', 1);
127
    }
128
129
    /**
130
     * {@inheritdoc}
131
     *
132
     * @see \Cerberus\CerberusInterface::reportSuccess()
133
     */
134
    public function reportSuccess($serviceName = null)
135
    {
136
        $this->setNamespace($serviceName);
137
        $this->storage->setItem('failures', 0);
138
    }
139
140
    /**
141
     * Sets the zend-cache storage namespace.
142
     *
143
     * @param string $serviceName
144
     */
145
    private function setNamespace($serviceName = null)
146
    {
147
        if ($serviceName === null) {
148
            $this->storage->getOptions()->setNamespace($this->defaultNamespace);
149
        } else {
150
            $this->storage->getOptions()->setNamespace($serviceName);
151
        }
152
    }
153
}
154