Skip to content

Commit

Permalink
Merge pull request #600 from sandervanhooft/redo_curl_retries
Browse files Browse the repository at this point in the history
Redo curl retries
  • Loading branch information
sandervanhooft authored Feb 8, 2022
2 parents 665e0c0 + 2eca8bd commit a358fd4
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 3 deletions.
7 changes: 7 additions & 0 deletions src/Exceptions/CurlConnectTimeoutException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Mollie\Api\Exceptions;

class CurlConnectTimeoutException extends ApiException
{
}
81 changes: 78 additions & 3 deletions src/HttpAdapter/CurlMollieHttpAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Composer\CaBundle\CaBundle;
use Mollie\Api\Exceptions\ApiException;
use Mollie\Api\Exceptions\CurlConnectTimeoutException;
use Mollie\Api\MollieApiClient;

final class CurlMollieHttpAdapter implements MollieHttpAdapterInterface
Expand All @@ -23,15 +24,51 @@ final class CurlMollieHttpAdapter implements MollieHttpAdapterInterface
*/
const HTTP_NO_CONTENT = 204;

/**
* The maximum number of retries
*/
const MAX_RETRIES = 5;

/**
* The amount of milliseconds the delay is being increased with on each retry.
*/
const DELAY_INCREASE_MS = 1000;

/**
* @param string $httpMethod
* @param string $url
* @param array $headers
* @param $httpBody
* @return \stdClass|null
* @return \stdClass|void|null
* @throws \Mollie\Api\Exceptions\ApiException
* @throws \Mollie\Api\Exceptions\CurlConnectTimeoutException
*/
public function send($httpMethod, $url, $headers, $httpBody)
{
for ($i = 0; $i <= self::MAX_RETRIES; $i++) {
usleep($i * self::DELAY_INCREASE_MS);

try {
return $this->attemptRequest($httpMethod, $url, $headers, $httpBody);
} catch (CurlConnectTimeoutException $e) {
// Nothing
}
}

throw new CurlConnectTimeoutException(
"Unable to connect to Mollie. Maximum number of retries (". self::MAX_RETRIES .") reached."
);
}

/**
* @param string $httpMethod
* @param string $url
* @param array $headers
* @param $httpBody
* @return \stdClass|void|null
* @throws \Mollie\Api\Exceptions\ApiException
*/
protected function attemptRequest($httpMethod, $url, $headers, $httpBody)
{
$curl = curl_init($url);
$headers["Content-Type"] = "application/json";
Expand Down Expand Up @@ -65,14 +102,23 @@ public function send($httpMethod, $url, $headers, $httpBody)
throw new \InvalidArgumentException("Invalid http method: ". $httpMethod);
}

$startTime = microtime(true);
$response = curl_exec($curl);
$endTime = microtime(true);

if ($response === false) {
throw new ApiException("Curl error: " . curl_error($curl));
$executionTime = $endTime - $startTime;
$curlErrorNumber = curl_errno($curl);
$curlErrorMessage = "Curl error: " . curl_error($curl);

if ($this->isConnectTimeoutError($curlErrorNumber, $executionTime)) {
throw new CurlConnectTimeoutException("Unable to connect to Mollie. " . $curlErrorMessage);
}

throw new ApiException($curlErrorMessage);
}

$statusCode = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);

curl_close($curl);

return $this->parseResponseBody($response, $statusCode, $httpBody);
Expand Down Expand Up @@ -100,6 +146,35 @@ public function supportsDebugging()
return false;
}

/**
* @param $curlErrorNumber
* @param $executionTime
* @return bool
*/
protected function isConnectTimeoutError($curlErrorNumber, $executionTime)
{
$connectErrors = [
\CURLE_COULDNT_RESOLVE_HOST => true,
\CURLE_COULDNT_CONNECT => true,
\CURLE_SSL_CONNECT_ERROR => true,
\CURLE_GOT_NOTHING => true,
];

if (isset($connectErrors[$curlErrorNumber])) {
return true;
};

if ($curlErrorNumber === \CURLE_OPERATION_TIMEOUTED) {
if ($executionTime > self::DEFAULT_TIMEOUT) {
return false;
}

return true;
}

return false;
}

/**
* @param string $response
* @param int $statusCode
Expand Down

0 comments on commit a358fd4

Please sign in to comment.