Completed
Push — master ( 19d06a...0345e1 )
by Jorge
01:51
created

TimeBackoff::getLastAttemptTime()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 8
ccs 6
cts 6
cp 1
crap 2
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace JVelasco\CircuitBreaker\AvailabilityStrategy;
4
5
use JVelasco\CircuitBreaker\AvailabilityStrategy;
6
use JVelasco\CircuitBreaker\StorageException;
7
8
class TimeBackoff implements AvailabilityStrategy
9
{
10
    const ATTEMPTS_KEY = "attempts";
11
    const LAST_ATTEMPT_TIME_KEY = "last_attempt";
12
13
    /** @var Storage */
14
    protected $storage;
15
    /** @var int */
16
    protected $maxFailures;
17
    /** @var int initial time to wait in milliseconds */
18
    protected $baseWaitTime;
19
    /** @var BackoffStrategy */
20
    private $backoffStrategy;
21
22 6
    public function __construct(
23
        Storage $storage,
24
        BackoffStrategy $backoffStrategy,
25
        int $maxFailures,
26
        int $baseWaitTime
27
    ) {
28 6
        $this->storage = $storage;
29 6
        $this->maxFailures = $maxFailures;
30 6
        $this->baseWaitTime = $baseWaitTime;
31 6
        $this->backoffStrategy = $backoffStrategy;
32 6
    }
33
34 6
    public function isAvailable(string $serviceName): bool
35
    {
36
        try {
37 6
            if ($this->storage->numberOfFailures($serviceName) < $this->maxFailures) {
38 2
                return true;
39
            }
40
41 4
            $attempt = $this->getLastAttempt($serviceName);
42 4
            if ($this->millisecondsSinceLastAttempt($serviceName) > $this->backoffStrategy->waitTime($attempt, $this->baseWaitTime)) {
43 2
                $this->saveAttempt($serviceName, $attempt+1);
44 2
                return true;
45
            }
46
47 2
            return false;
48 1
        } catch (StorageException $ex) {
49 1
            return true;
50
        }
51
    }
52
53 4
    private function getLastAttemptTime(string $serviceName): int
54
    {
55 4
        $lastTryTimestamp = $this->storage->getStrategyData(
56 4
            $this,
57 4
            $serviceName,
58 4
            self::LAST_ATTEMPT_TIME_KEY
59
        );
60 4
        return $lastTryTimestamp ? $lastTryTimestamp : $this->now();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $lastTryTimestamp...imestamp : $this->now() could return the type string which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
61
    }
62
63 4
    private function now(): int
64
    {
65 4
        return floor(microtime(true) * 1000);
0 ignored issues
show
Bug Best Practice introduced by
The expression return floor(microtime(true) * 1000) returns the type double which is incompatible with the type-hinted return integer.
Loading history...
66
    }
67
68 4
    private function getLastAttempt($serviceName): int
69
    {
70 4
        return (int) $this->storage->getStrategyData($this, $serviceName, self::ATTEMPTS_KEY);
71
    }
72
73 4
    public function getId(): string
74
    {
75 4
        return $this->backoffStrategy->id();
76
    }
77
78 4
    private function millisecondsSinceLastAttempt(string $serviceName): int
79
    {
80 4
        $lastAttempt = $this->getLastAttemptTime($serviceName);
81 4
        return $this->now() - $lastAttempt;
82
    }
83
84 2
    private function saveAttempt(string $serviceName, int $attempt)
85
    {
86 2
        $this->storage->saveStrategyData(
87 2
            $this,
88 2
            $serviceName,
89 2
            self::ATTEMPTS_KEY,
90 2
            $attempt
91
        );
92 2
        $this->storage->saveStrategyData(
93 2
            $this,
94 2
            $serviceName,
95 2
            self::LAST_ATTEMPT_TIME_KEY,
96 2
            $this->now()
97
        );
98 2
        $this->storage->resetFailuresCounter($serviceName);
99 2
    }
100
}
101