CircuitBreaker   A
last analyzed

Complexity

Total Complexity 15

Size/Duplication

Total Lines 91
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 15
eloc 30
c 1
b 0
f 0
dl 0
loc 91
rs 10

10 Methods

Rating   Name   Duplication   Size   Complexity  
A areAllServicesAvailable() 0 9 3
A registerService() 0 3 1
A setOpenCircuit() 0 3 1
A getRegisteredServiceNames() 0 3 1
A reportSuccess() 0 5 1
A isCircuitOpen() 0 3 1
A isServiceAvailable() 0 15 2
A getService() 0 12 2
A reportFailure() 0 12 2
A __construct() 0 3 1
1
<?php declare(strict_types=1);
2
3
namespace HolidayPirates\CircuitBreaker;
4
5
use HolidayPirates\CircuitBreaker\Service\ServiceInterface;
6
use HolidayPirates\CircuitBreaker\Storage\StorageInterface;
7
8
class CircuitBreaker implements CircuitBreakerInterface
9
{
10
    private $storage;
11
    private $services = [];
12
13
    public function __construct(StorageInterface $storage)
14
    {
15
        $this->storage = $storage;
16
    }
17
18
    public function registerService(ServiceInterface $service): void
19
    {
20
        $this->services[$service->getIdentifier()] = $service;
21
    }
22
23
    public function isServiceAvailable(string $serviceName): bool
24
    {
25
        $service = $this->getService($serviceName);
26
27
        if ($this->isCircuitOpen($service)) {
28
            return false;
29
        }
30
31
        /**
32
         * If we wanted a full 3-state CircuitBreaker implementation as described by Fowler, it is in here
33
         * that we can add the logic for the "Half-open circuit", which would allow a smaller number of requests
34
         * to go through before we really close the circuit.
35
         */
36
37
        return true;
38
    }
39
40
    public function reportFailure(string $serviceName): void
41
    {
42
        $service = $this->getService($serviceName);
43
        $amountOfFailures = $this->storage->getAmountOfFailures($service);
44
45
        if ($amountOfFailures >= $service->getMaxFailures()) {
46
            $this->setOpenCircuit($service);
47
48
            return;
49
        }
50
51
        $this->storage->incrementAmountOfFailures($service);
52
    }
53
54
    public function reportSuccess(string $serviceName): void
55
    {
56
        $service = $this->getService($serviceName);
57
58
        $this->storage->incrementAmountOfSuccess($service);
59
    }
60
61
    public function areAllServicesAvailable(): bool
62
    {
63
        foreach ($this->getRegisteredServiceNames() as $serviceName) {
64
            if (!$this->isServiceAvailable($serviceName)) {
65
                return false;
66
            }
67
        }
68
69
        return true;
70
    }
71
72
    public function getRegisteredServiceNames(): array
73
    {
74
        return array_keys($this->services);
75
    }
76
77
    private function getService(string $serviceName): ServiceInterface
78
    {
79
        if (false === isset($this->services[$serviceName])) {
80
            throw new \LogicException(
81
                sprintf(
82
                    'Service not found. Did you forgot to call registerService(%s) ?',
83
                    $serviceName
84
                )
85
            );
86
        }
87
88
        return $this->services[$serviceName];
89
    }
90
91
    private function setOpenCircuit(ServiceInterface $service): void
92
    {
93
        $this->storage->setOpenCircuit($service);
94
    }
95
96
    private function isCircuitOpen(ServiceInterface $service): bool
97
    {
98
        return $this->storage->isCircuitOpen($service);
99
    }
100
}
101