Failed Conditions
Pull Request — master (#43)
by
unknown
05:55
created

RetryStrategy   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 85
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
wmc 21
lcom 1
cbo 2
dl 0
loc 85
rs 10
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A shouldRetry() 0 8 2
A retryLimit() 0 4 2
A canRetry() 0 4 2
A errorCodeStrategy() 0 17 3
A applyStrategy() 0 9 3
A changeServer() 0 12 4
A reconnect() 0 6 2
A __destruct() 0 5 2
errorCodeStrategies() 0 1 ?
errorCode() 0 1 ?
1
<?php
2
3
namespace Ez\DbLinker\RetryStrategy;
4
5
use Exception;
6
use stdClass;
7
use Ez\DbLinker\Driver\Connection\MasterSlavesConnection;
8
use Ez\DbLinker\Driver\Connection\RetryConnection;
9
10
trait RetryStrategy
11
{
12
    private $retryLimit;
13
14
    public function __construct($retryLimit = INF)
15
    {
16
        $this->retryLimit = $retryLimit;
17
    }
18
19
    public function shouldRetry(Exception $exception, RetryConnection $connection) {
20
        if (!$this->canRetry($connection)) {
21
            return false;
22
        }
23
        $strategy = $this->errorCodeStrategy($this->errorCode($exception));
24
        $res = $this->applyStrategy($strategy, $connection);
25
        return $res;
26
    }
27
28
    public function retryLimit()
29
    {
30
        return $this->retryLimit > 0 ? (int) $this->retryLimit : 0;
31
    }
32
33
    private function canRetry(RetryConnection $connection)
34
    {
35
        return $this->retryLimit > 0 && $connection->transactionLevel() === 0;
36
    }
37
38
    private function errorCodeStrategy($errorCode)
39
    {
40
        $strategy = (object) [
41
            'retry' => true,
42
            'wait' => 0,
43
            'changeServer' => false,
44
            'reconnect' => false,
45
        ];
46
        $errorCodeStrategies = $this->errorCodeStrategies();
47
        if (array_key_exists($errorCode, $errorCodeStrategies)) {
48
            foreach ($errorCodeStrategies[$errorCode] as $behavior => $value) {
49
                $strategy->$behavior = $value;
50
            }
51
            return $strategy;
52
        }
53
        return (object) ['retry' => false];
54
    }
55
56
    private function applyStrategy(stdClass $strategy, RetryConnection $connection) {
57
        if ($strategy->retry === false || !$this->changeServer($strategy, $connection)) {
58
            return false;
59
        }
60
        sleep($strategy->wait);
61
        $this->reconnect($strategy, $connection);
62
        $this->retryLimit--;
63
        return true;
64
    }
65
66
    private function changeServer(stdClass $strategy, RetryConnection $connection)
67
    {
68
        if (!$strategy->changeServer) {
69
            return true;
70
        }
71
        $wrappedConnection = $connection->wrappedConnection();
72
        if ($wrappedConnection instanceof MasterSlavesConnection && !$wrappedConnection->isConnectedToMaster()) {
73
            $wrappedConnection->disableCurrentSlave();
74
            return true;
75
        }
76
        return false;
77
    }
78
79
    private function reconnect(stdClass $strategy, RetryConnection $connection)
80
    {
81
        if ($strategy->reconnect) {
82
            $connection->close();
83
        }
84
    }
85
86
    public function __destruct() {
87
        if ($connection !== null) {
88
            $connection->close();
0 ignored issues
show
Bug introduced by
The variable $connection does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
89
        }
90
    }
91
92
    protected abstract function errorCodeStrategies();
93
    protected abstract function errorCode(Exception $exception);
94
}
95