Completed
Push — fixTravisCoverageReporting ( 3b7662...4fbbcc )
by adam
02:51
created

MiddlewareFactory::newRetryDecider()   C

Complexity

Conditions 10
Paths 1

Size

Total Lines 61
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 40
CRAP Score 10

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 61
ccs 40
cts 40
cp 1
rs 6.4758
cc 10
eloc 34
nc 1
nop 0
crap 10

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 8
	public function __construct() {
27 8
		$this->logger = new NullLogger();
28 8
	}
29
30
	public function setLogger( LoggerInterface $logger ) {
31
		$this->logger = $logger;
32
	}
33
34
	/**
35
	 * @return callable
36
	 */
37 8
	public function retry() {
38 8
		return Middleware::retry( $this->newRetryDecider() );
39
	}
40
41
	/**
42
	 * @return callable
43
	 */
44
	private function newRetryDecider() {
45 8
		return function (
46
			$retries,
47
			Request $request,
48
			Response $response = null,
49
			RequestException $exception = null
50
		) {
51
			// Don't retry if we have run out of retries
52 8
			if ( $retries >= 5 ) {
53 2
				return false;
54
			}
55
56 8
			$shouldRetry = false;
57
58
			// Retry connection exceptions
59 8
			if( $exception instanceof ConnectException ) {
60 4
				$shouldRetry = true;
61 4
			}
62
63 8
			if( $response ) {
64 6
				$headers = $response->getHeaders();
65
66
				// Retry on server errors
67 6
				if( $response->getStatusCode() >= 500 ) {
68 2
					$shouldRetry = true;
69 2
				}
70
71
				// Retry if we have a response with an API error worth retrying
72 6
				if ( array_key_exists( 'mediawiki-api-error', $headers ) ) {
73 2
					foreach( $headers['mediawiki-api-error'] as $mediawikiApiErrorHeader ) {
74 2
						if ( in_array(
75 2
							$mediawikiApiErrorHeader,
76
							array(
77 2
								'ratelimited',
78 2
								'readonly',
79 2
								'internal_api_error_DBQueryError',
80 2
							)
81 2
						) ) {
82 2
							$shouldRetry = true;
83 2
						}
84 2
					}
85 2
				}
86 6
			}
87
88
			// Log if we are retrying
89 8
			if( $shouldRetry ) {
90 8
				$this->logger->warning(
91 8
					sprintf(
92 8
						'Retrying %s %s %s/5, %s',
93 8
						$request->getMethod(),
94 8
						$request->getUri(),
95 8
						$retries + 1,
96 8
						$response ? 'status code: ' . $response->getStatusCode() :
97 4
							$exception->getMessage()
0 ignored issues
show
Bug introduced by
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...
98 8
					)
99 8
				);
100 8
			}
101
102 8
			return $shouldRetry;
103 8
		};
104
	}
105
106
}
107