version 1.5
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
namespace InfluxDB2;
|
||||
|
||||
use Http\Client\Exception\NetworkException;
|
||||
|
||||
/**
|
||||
* Exponential random write retry.
|
||||
*/
|
||||
class WriteRetry
|
||||
{
|
||||
private $maxRetries;
|
||||
private $retryInterval;
|
||||
private $maxRetryDelay;
|
||||
private $exponentialBase;
|
||||
private $jitterInterval;
|
||||
private $maxRetryTime;
|
||||
private $retryTimout;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* WriteRetry constructor.
|
||||
*
|
||||
* @param int $maxRetries max number of retries when write fails
|
||||
* @param int $retryInterval number of milliseconds to retry unsuccessful write,
|
||||
* The retry interval is used when the InfluxDB server does not specify "Retry-After" header.
|
||||
* @param int $maxRetryDelay maximum delay when retrying write in milliseconds
|
||||
* @param int $exponentialBase the base for the exponential retry delay, the next delay is computed using
|
||||
* random exponential backoff as a random value within the interval
|
||||
* ``retryInterval * exponentialBase^(attempts-1)`` and
|
||||
* ``retryInterval * exponentialBase^(attempts)``.
|
||||
* Example for ``retryInterval=5000, exponentialBase=2, maxRetryDelay=125000, total=5``
|
||||
* Retry delays are random distributed values within the ranges of
|
||||
* ``[5000-10000, 10000-20000, 20000-40000, 40000-80000, 80000-125000]``
|
||||
*
|
||||
* @param int $maxRetryTime maximum total time when retrying write in milliseconds
|
||||
* @param int $jitterInterval the number of milliseconds before the data is written increased by a random amount
|
||||
* @param array $options Client options with logFile.
|
||||
*/
|
||||
public function __construct(
|
||||
int $maxRetries = 5,
|
||||
int $retryInterval = 5000,
|
||||
int $maxRetryDelay = 125000,
|
||||
int $exponentialBase = 2,
|
||||
int $maxRetryTime = 180000,
|
||||
int $jitterInterval = 0,
|
||||
array $options = []
|
||||
) {
|
||||
$this->maxRetries = $maxRetries;
|
||||
$this->retryInterval = $retryInterval;
|
||||
$this->maxRetryDelay = $maxRetryDelay;
|
||||
$this->maxRetryTime = $maxRetryTime;
|
||||
$this->exponentialBase = $exponentialBase;
|
||||
$this->jitterInterval = $jitterInterval;
|
||||
$this->options = $options;
|
||||
|
||||
//retry timout
|
||||
$this->retryTimout = microtime(true) * 1000 + $maxRetryTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiException
|
||||
*/
|
||||
public function retry($callable, $attempts = 0)
|
||||
{
|
||||
try {
|
||||
return call_user_func($callable);
|
||||
} catch (ApiException $e) {
|
||||
$error = $e->getResponseBody() ?? $e->getMessage();
|
||||
|
||||
if (!$this->isRetryable($e)) {
|
||||
throw $e;
|
||||
}
|
||||
$attempts++;
|
||||
if ($attempts > $this->maxRetries) {
|
||||
DefaultApi::log("ERROR", "Maximum retry attempts reached", $this->options);
|
||||
throw $e;
|
||||
}
|
||||
|
||||
// throws exception when max retry time is exceeded
|
||||
if (microtime(true) * 1000 > $this->retryTimout) {
|
||||
DefaultApi::log("ERROR", "Maximum retry time $this->maxRetryTime ms exceeded", $this->options);
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$headers = $e->getResponseHeaders();
|
||||
if ($headers != null && array_key_exists('Retry-After', $headers)) {
|
||||
//jitter add in microseconds
|
||||
$jitterMicro = rand(0, $this->jitterInterval) * 1000;
|
||||
$timeout = (int)$headers['Retry-After'][0] * 1000000.0 + $jitterMicro;
|
||||
} else {
|
||||
$timeout = $this->getBackoffTime($attempts) * 1000;
|
||||
}
|
||||
|
||||
$timeoutInSec = $timeout / 1000000.0;
|
||||
|
||||
$message = "The retryable error occurred during writing of data. Reason: '$error'. Retry in: {$timeoutInSec}s.";
|
||||
DefaultApi::log("WARNING", $message, $this->options);
|
||||
usleep($timeout);
|
||||
$this->retry($callable, $attempts);
|
||||
}
|
||||
}
|
||||
|
||||
public function isRetryable(ApiException $e): bool
|
||||
{
|
||||
$code = $e->getCode();
|
||||
if (($code == null || $code < 429) &&
|
||||
!($e->getPrevious() instanceof NetworkException)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getBackoffTime(int $attempt)
|
||||
{
|
||||
$range_start = $this->retryInterval;
|
||||
$range_stop = $this->retryInterval * $this->exponentialBase;
|
||||
|
||||
$i = 1;
|
||||
while ($i < $attempt) {
|
||||
$i += 1;
|
||||
$range_start = $range_stop;
|
||||
$range_stop = $range_stop * $this->exponentialBase;
|
||||
if ($range_stop > $this->maxRetryDelay) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($range_stop > $this->maxRetryDelay) {
|
||||
$range_stop = $this->maxRetryDelay;
|
||||
}
|
||||
return $range_start + ($range_stop - $range_start) * (rand(0, 1000) / 1000);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user