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

src/RetryStrategy/RetryStrategy.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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
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