Completed
Push — master ( 9c21b6...43c791 )
by David
04:48
created

HttpClientPoolItem   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 146
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 97.87%

Importance

Changes 0
Metric Value
wmc 15
lcom 1
cbo 3
dl 0
loc 146
ccs 46
cts 47
cp 0.9787
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A sendRequest() 0 19 3
A sendAsyncRequest() 0 19 2
A isDisabled() 0 17 4
A getSendingRequestCount() 0 4 1
A incrementRequestCount() 0 4 1
A decrementRequestCount() 0 4 1
A enable() 0 4 1
A disable() 0 4 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Http\Client\Common\HttpClientPool;
6
7
use Http\Client\Common\FlexibleHttpClient;
8
use Http\Client\HttpAsyncClient;
9
use Http\Client\HttpClient;
10
use Psr\Http\Client\ClientInterface;
11
use Psr\Http\Message\RequestInterface;
12
use Http\Client\Exception;
13
use Psr\Http\Message\ResponseInterface;
14
15
/**
16
 * A HttpClientPoolItem represent a HttpClient inside a Pool.
17
 *
18
 * It is disabled when a request failed and can be reenabled after a certain number of seconds.
19
 * It also keep tracks of the current number of open requests the client is currently being sending
20
 * (only usable for async method).
21
 *
22
 * This class is used internally in the client pools and is not supposed to be used anywhere else.
23
 *
24
 * @final
25
 *
26
 * @internal
27
 *
28
 * @author Joel Wurtz <[email protected]>
29
 */
30
class HttpClientPoolItem implements HttpClient, HttpAsyncClient
31
{
32
    /**
33
     * @var int Number of request this client is currently sending
34
     */
35
    private $sendingRequestCount = 0;
36
37
    /**
38
     * @var \DateTime|null Time when this client has been disabled or null if enable
39
     */
40
    private $disabledAt;
41
42
    /**
43
     * Number of seconds until this client is enabled again after an error.
44
     *
45
     * null: never reenable this client.
46
     *
47
     * @var int|null
48
     */
49
    private $reenableAfter;
50
51
    /**
52
     * @var FlexibleHttpClient A http client responding to async and sync request
53
     */
54
    private $client;
55
56
    /**
57
     * @param ClientInterface|HttpAsyncClient $client
58
     * @param null|int                        $reenableAfter Number of seconds until this client is enabled again after an error
59
     */
60 23
    public function __construct($client, $reenableAfter = null)
61
    {
62 23
        $this->client = new FlexibleHttpClient($client);
63 23
        $this->reenableAfter = $reenableAfter;
64 23
    }
65
66
    /**
67
     * {@inheritdoc}
68
     */
69 13
    public function sendRequest(RequestInterface $request): ResponseInterface
70
    {
71 13
        if ($this->isDisabled()) {
72 1
            throw new Exception\RequestException('Cannot send the request as this client has been disabled', $request);
73
        }
74
75
        try {
76 13
            $this->incrementRequestCount();
77 13
            $response = $this->client->sendRequest($request);
78 5
            $this->decrementRequestCount();
79 8
        } catch (Exception $e) {
80 8
            $this->disable();
81 8
            $this->decrementRequestCount();
82
83 8
            throw $e;
84
        }
85
86 5
        return $response;
87
    }
88
89
    /**
90
     * {@inheritdoc}
91
     */
92 8
    public function sendAsyncRequest(RequestInterface $request)
93
    {
94 8
        if ($this->isDisabled()) {
95 1
            throw new Exception\RequestException('Cannot send the request as this client has been disabled', $request);
96
        }
97
98 8
        $this->incrementRequestCount();
99
100
        return $this->client->sendAsyncRequest($request)->then(function ($response) {
101 1
            $this->decrementRequestCount();
102
103 1
            return $response;
104
        }, function ($exception) {
105 2
            $this->disable();
106 2
            $this->decrementRequestCount();
107
108 2
            throw $exception;
109 8
        });
110
    }
111
112
    /**
113
     * Whether this client is disabled or not.
114
     *
115
     * If the client was disabled, calling this method checks if the client can
116
     * be reenabled and if so enables it.
117
     */
118 21
    public function isDisabled(): bool
119
    {
120 21
        if (null !== $this->reenableAfter && null !== $this->disabledAt) {
121
            // Reenable after a certain time
122 5
            $now = new \DateTime();
123
124 5
            if (($now->getTimestamp() - $this->disabledAt->getTimestamp()) >= $this->reenableAfter) {
125 5
                $this->enable();
126
127 5
                return false;
128
            }
129
130
            return true;
131
        }
132
133 21
        return null !== $this->disabledAt;
134
    }
135
136
    /**
137
     * Get current number of request that are currently being sent by the underlying HTTP client.
138
     */
139 2
    public function getSendingRequestCount(): int
140
    {
141 2
        return $this->sendingRequestCount;
142
    }
143
144
    /**
145
     * Increment the request count.
146
     */
147 21
    private function incrementRequestCount()
148
    {
149 21
        ++$this->sendingRequestCount;
150 21
    }
151
152
    /**
153
     * Decrement the request count.
154
     */
155 16
    private function decrementRequestCount()
156
    {
157 16
        --$this->sendingRequestCount;
158 16
    }
159
160
    /**
161
     * Enable the current client.
162
     */
163 5
    private function enable()
164
    {
165 5
        $this->disabledAt = null;
166 5
    }
167
168
    /**
169
     * Disable the current client.
170
     */
171 10
    private function disable()
172
    {
173 10
        $this->disabledAt = new \DateTime('now');
174 10
    }
175
}
176