diff --git a/lib/Error/RequestIdConflict.php b/lib/Error/RequestIdConflict.php new file mode 100644 index 00000000..a06008b0 --- /dev/null +++ b/lib/Error/RequestIdConflict.php @@ -0,0 +1,15 @@ +requestId = $requestId; + } +} diff --git a/lib/HttpClient.php b/lib/HttpClient.php index b0d8379d..1c36a9bc 100644 --- a/lib/HttpClient.php +++ b/lib/HttpClient.php @@ -37,6 +37,7 @@ public function request($callId, $method, $url, $headers, $params, $responseClas if ($this->curlOptions) { $opts += $this->curlOptions; } + $opts += array(CURLOPT_CONNECTTIMEOUT => 5, CURLOPT_TIMEOUT => 5); curl_setopt_array($curl, $opts); diff --git a/lib/PartnerAPI.php b/lib/PartnerAPI.php index c4e4bb59..bb1613b5 100644 --- a/lib/PartnerAPI.php +++ b/lib/PartnerAPI.php @@ -18,6 +18,7 @@ class PartnerAPI private $curlOptions = array(); private $acceptLanguage; + private $maxRetries = 2; private $appName; private $appVersion; @@ -129,16 +130,55 @@ public function send($request) if ($this->acceptLanguage) { array_push($headers, 'Accept-Language: ' . $this->acceptLanguage); } - array_push($headers, 'User-Agent: ' . $this->computeUserAgent()); - return $this->clientInstance->request( - $request->getCallId(), - $request->getMethod(), - $this->apiBase . $request->getPath(), - $headers, - $request->getParams() + $request->getDefaultParams(), - $request->responseClass - ); + $retry = 0; + while (true) { + try { + return $this->clientInstance->request( + $request->getCallId(), + $request->getMethod(), + $this->apiBase . $request->getPath(), + $headers, + $request->getParams() + $request->getDefaultParams(), + $request->responseClass + ); + } catch (Error\ApiConnection $e) { + if (!$request->isRetriable()) + { + throw $e; + } + + // Retry when timeout + if ($e->errno != CURLE_OPERATION_TIMEDOUT || $retry >= $this->maxRetries) + { + throw $e; + } + } catch (Error\HttpRequest $e) { + if (is_array($e->response) + && array_key_exists('type', $e->response) + && $e->response['type'] === 'request_id_conflict') + { + throw new Error\RequestIdConflict( + $e->code, + $e->rawResponse, + $e->response, + $request->getParams()['request_id'] + ); + } + if (!$request->isRetriable()) + { + throw $e; + } + // Retry on 503 + if ($e->code != 503 || $retry >= $this->maxRetries) + { + throw $e; + } + sleep(3); + } + ++$retry; + $request->setCallId(null); // Re-generate the call ID + } } } diff --git a/lib/Request/Base.php b/lib/Request/Base.php index 28b72fb4..0b2c55e1 100644 --- a/lib/Request/Base.php +++ b/lib/Request/Base.php @@ -24,7 +24,7 @@ public function getCallId() public function setCallId($newCallId) { - $this->callId = $newCallId; + $this->callId = $newCallId || Uuid::uuid4(); } public function getMethod() @@ -51,4 +51,13 @@ public function getParams() { return array(); } + + public function isRetriable() + { + $params = $this->getParams(); + return ( + $this->method == 'GET' || $this->method == 'PATCH' + || (is_array($params) && array_key_exists('request_id', $params)) + ); + } }