Completed
Push — master ( 75ba53...89ec26 )
by adam
04:50 queued 12s
created

src/Guzzle/MiddlewareFactory.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 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
It seems like $exception is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
129
					)
130
				);
131
			}
132
133 6
			return $shouldRetry;
134 6
		};
135
	}
136
137
}
138