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 Mediawiki\Api\Guzzle; |
||
4 | |||
5 | use GuzzleHttp\Exception\ConnectException; |
||
6 | use GuzzleHttp\Exception\RequestException; |
||
7 | use GuzzleHttp\Middleware; |
||
8 | use GuzzleHttp\Psr7\Request; |
||
9 | use GuzzleHttp\Psr7\Response; |
||
10 | use Psr\Log\LoggerAwareInterface; |
||
11 | use Psr\Log\LoggerInterface; |
||
12 | use Psr\Log\NullLogger; |
||
13 | |||
14 | /** |
||
15 | * @access private |
||
16 | * |
||
17 | * @author Addshore |
||
18 | */ |
||
19 | class MiddlewareFactory implements LoggerAwareInterface { |
||
20 | |||
21 | /** |
||
22 | * @var LoggerInterface |
||
23 | */ |
||
24 | private $logger; |
||
25 | |||
26 | 6 | public function __construct() { |
|
27 | 6 | $this->logger = new NullLogger(); |
|
28 | 6 | } |
|
29 | |||
30 | public function setLogger( LoggerInterface $logger ) { |
||
31 | $this->logger = $logger; |
||
32 | } |
||
33 | |||
34 | /** |
||
35 | * @access private |
||
36 | * |
||
37 | * @param bool $delay default to true, can be false to speed up tests |
||
38 | * |
||
39 | * @return callable |
||
40 | */ |
||
41 | 6 | public function retry( $delay = true ) { |
|
42 | 6 | if( $delay ) { |
|
43 | 1 | return Middleware::retry( $this->newRetryDecider(), $this->getRetryDelay() ); |
|
44 | } else { |
||
45 | 5 | return Middleware::retry( $this->newRetryDecider() ); |
|
46 | } |
||
47 | } |
||
48 | |||
49 | /** |
||
50 | * Returns a method that takes the number of retries and returns the number of miliseconds |
||
51 | * to wait |
||
52 | * |
||
53 | * @return callable |
||
54 | */ |
||
55 | 1 | private function getRetryDelay() { |
|
56 | return function( $numberOfRetries ) { |
||
57 | 1 | return 1000 * $numberOfRetries; |
|
58 | 1 | }; |
|
59 | } |
||
60 | |||
61 | /** |
||
62 | * @return callable |
||
63 | */ |
||
64 | private function newRetryDecider() { |
||
65 | 6 | return function ( |
|
66 | $retries, |
||
67 | Request $request, |
||
68 | Response $response = null, |
||
69 | RequestException $exception = null |
||
70 | ) { |
||
71 | // Don't retry if we have run out of retries |
||
72 | 6 | if ( $retries >= 5 ) { |
|
73 | 1 | return false; |
|
74 | } |
||
75 | |||
76 | 6 | $shouldRetry = false; |
|
77 | |||
78 | // Retry connection exceptions |
||
79 | 6 | if( $exception instanceof ConnectException ) { |
|
80 | 3 | $shouldRetry = true; |
|
81 | } |
||
82 | |||
83 | 6 | if( $response ) { |
|
84 | 5 | $headers = $response->getHeaders(); |
|
85 | 5 | $data = json_decode( $response->getBody(), true ); |
|
86 | |||
87 | // Retry on server errors |
||
88 | 5 | if( $response->getStatusCode() >= 500 ) { |
|
89 | 1 | $shouldRetry = true; |
|
90 | } |
||
91 | |||
92 | 5 | if ( array_key_exists( 'mediawiki-api-error', $headers ) ) { |
|
93 | 2 | foreach( $headers['mediawiki-api-error'] as $mediawikiApiErrorHeader ) { |
|
94 | if ( |
||
95 | // Retry if we have a response with an API error worth retrying |
||
96 | 2 | in_array( |
|
97 | $mediawikiApiErrorHeader, |
||
98 | array( |
||
99 | 2 | 'ratelimited', |
|
100 | 'readonly', |
||
101 | 'internal_api_error_DBQueryError', |
||
102 | ) |
||
103 | ) |
||
104 | || |
||
105 | // Or if we have been stopped from saving as an 'anti-abuse measure' |
||
106 | // Note: this tries to match "actionthrottledtext" i18n messagae for mediawiki |
||
107 | ( |
||
108 | 2 | $mediawikiApiErrorHeader == 'failed-save' && |
|
109 | 2 | strstr( $data['error']['info'], 'anti-abuse measure' ) |
|
110 | ) |
||
111 | ) { |
||
112 | 2 | $shouldRetry = true; |
|
113 | } |
||
114 | |||
115 | } |
||
116 | } |
||
117 | } |
||
118 | |||
119 | // Log if we are retrying |
||
120 | 6 | if( $shouldRetry ) { |
|
121 | 6 | $this->logger->warning( |
|
122 | sprintf( |
||
123 | 6 | 'Retrying %s %s %s/5, %s', |
|
124 | 6 | $request->getMethod(), |
|
125 | 6 | $request->getUri(), |
|
126 | 6 | $retries + 1, |
|
127 | 6 | $response ? 'status code: ' . $response->getStatusCode() : |
|
128 | 6 | $exception->getMessage() |
|
0 ignored issues
–
show
|
|||
129 | ) |
||
130 | ); |
||
131 | } |
||
132 | |||
133 | 6 | return $shouldRetry; |
|
134 | 6 | }; |
|
135 | } |
||
136 | |||
137 | } |
||
138 |
If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe: