summaryrefslogtreecommitdiff
path: root/vendor/aws/aws-sdk-php/src/Retry
diff options
context:
space:
mode:
authorAndrew Dolgov <[email protected]>2022-11-23 21:14:33 +0300
committerAndrew Dolgov <[email protected]>2022-11-23 21:14:33 +0300
commit0c8af4992cb0f7589dcafaad65ada12753c64594 (patch)
tree18e83d068c3e7dd2499331de977782b382279396 /vendor/aws/aws-sdk-php/src/Retry
initial
Diffstat (limited to 'vendor/aws/aws-sdk-php/src/Retry')
-rw-r--r--vendor/aws/aws-sdk-php/src/Retry/Configuration.php61
-rw-r--r--vendor/aws/aws-sdk-php/src/Retry/ConfigurationInterface.php30
-rw-r--r--vendor/aws/aws-sdk-php/src/Retry/ConfigurationProvider.php222
-rw-r--r--vendor/aws/aws-sdk-php/src/Retry/Exception/ConfigurationException.php14
-rw-r--r--vendor/aws/aws-sdk-php/src/Retry/QuotaManager.php86
-rw-r--r--vendor/aws/aws-sdk-php/src/Retry/RateLimiter.php182
-rw-r--r--vendor/aws/aws-sdk-php/src/Retry/RetryHelperTrait.php56
7 files changed, 651 insertions, 0 deletions
diff --git a/vendor/aws/aws-sdk-php/src/Retry/Configuration.php b/vendor/aws/aws-sdk-php/src/Retry/Configuration.php
new file mode 100644
index 0000000..aa370c4
--- /dev/null
+++ b/vendor/aws/aws-sdk-php/src/Retry/Configuration.php
@@ -0,0 +1,61 @@
+<?php
+namespace Aws\Retry;
+
+use Aws\Retry\Exception\ConfigurationException;
+
+class Configuration implements ConfigurationInterface
+{
+ private $mode;
+ private $maxAttempts;
+ private $validModes = [
+ 'legacy',
+ 'standard',
+ 'adaptive'
+ ];
+
+ public function __construct($mode = 'legacy', $maxAttempts = 3)
+ {
+ $mode = strtolower($mode);
+ if (!in_array($mode, $this->validModes)) {
+ throw new ConfigurationException("'{$mode}' is not a valid mode."
+ . " The mode has to be 'legacy', 'standard', or 'adaptive'.");
+ }
+ if (!is_numeric($maxAttempts)
+ || intval($maxAttempts) != $maxAttempts
+ || $maxAttempts < 1
+ ) {
+ throw new ConfigurationException("The 'maxAttempts' parameter has"
+ . " to be an integer >= 1.");
+ }
+
+ $this->mode = $mode;
+ $this->maxAttempts = intval($maxAttempts);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getMode()
+ {
+ return $this->mode;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getMaxAttempts()
+ {
+ return $this->maxAttempts;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function toArray()
+ {
+ return [
+ 'mode' => $this->getMode(),
+ 'max_attempts' => $this->getMaxAttempts(),
+ ];
+ }
+}
diff --git a/vendor/aws/aws-sdk-php/src/Retry/ConfigurationInterface.php b/vendor/aws/aws-sdk-php/src/Retry/ConfigurationInterface.php
new file mode 100644
index 0000000..3f57b62
--- /dev/null
+++ b/vendor/aws/aws-sdk-php/src/Retry/ConfigurationInterface.php
@@ -0,0 +1,30 @@
+<?php
+namespace Aws\Retry;
+
+/**
+ * Provides access to retry configuration
+ */
+interface ConfigurationInterface
+{
+ /**
+ * Returns the retry mode. Available modes include 'legacy', 'standard', and
+ * 'adapative'.
+ *
+ * @return string
+ */
+ public function getMode();
+
+ /**
+ * Returns the maximum number of attempts that will be used for a request
+ *
+ * @return string
+ */
+ public function getMaxAttempts();
+
+ /**
+ * Returns the configuration as an associative array
+ *
+ * @return array
+ */
+ public function toArray();
+}
diff --git a/vendor/aws/aws-sdk-php/src/Retry/ConfigurationProvider.php b/vendor/aws/aws-sdk-php/src/Retry/ConfigurationProvider.php
new file mode 100644
index 0000000..db641f2
--- /dev/null
+++ b/vendor/aws/aws-sdk-php/src/Retry/ConfigurationProvider.php
@@ -0,0 +1,222 @@
+<?php
+namespace Aws\Retry;
+
+use Aws\AbstractConfigurationProvider;
+use Aws\CacheInterface;
+use Aws\ConfigurationProviderInterface;
+use Aws\Retry\Exception\ConfigurationException;
+use GuzzleHttp\Promise;
+use GuzzleHttp\Promise\PromiseInterface;
+
+/**
+ * A configuration provider is a function that returns a promise that is
+ * fulfilled with a {@see \Aws\Retry\ConfigurationInterface}
+ * or rejected with an {@see \Aws\Retry\Exception\ConfigurationException}.
+ *
+ * <code>
+ * use Aws\Sts\RegionalEndpoints\ConfigurationProvider;
+ * $provider = ConfigurationProvider::defaultProvider();
+ * // Returns a ConfigurationInterface or throws.
+ * $config = $provider()->wait();
+ * </code>
+ *
+ * Configuration providers can be composed to create configuration using
+ * conditional logic that can create different configurations in different
+ * environments. You can compose multiple providers into a single provider using
+ * {@see \Aws\Retry\ConfigurationProvider::chain}. This function
+ * accepts providers as variadic arguments and returns a new function that will
+ * invoke each provider until a successful configuration is returned.
+ *
+ * <code>
+ * // First try an INI file at this location.
+ * $a = ConfigurationProvider::ini(null, '/path/to/file.ini');
+ * // Then try an INI file at this location.
+ * $b = ConfigurationProvider::ini(null, '/path/to/other-file.ini');
+ * // Then try loading from environment variables.
+ * $c = ConfigurationProvider::env();
+ * // Combine the three providers together.
+ * $composed = ConfigurationProvider::chain($a, $b, $c);
+ * // Returns a promise that is fulfilled with a configuration or throws.
+ * $promise = $composed();
+ * // Wait on the configuration to resolve.
+ * $config = $promise->wait();
+ * </code>
+ */
+class ConfigurationProvider extends AbstractConfigurationProvider
+ implements ConfigurationProviderInterface
+{
+ const DEFAULT_MAX_ATTEMPTS = 3;
+ const DEFAULT_MODE = 'legacy';
+ const ENV_MAX_ATTEMPTS = 'AWS_MAX_ATTEMPTS';
+ const ENV_MODE = 'AWS_RETRY_MODE';
+ const ENV_PROFILE = 'AWS_PROFILE';
+ const INI_MAX_ATTEMPTS = 'max_attempts';
+ const INI_MODE = 'retry_mode';
+
+ public static $cacheKey = 'aws_retries_config';
+
+ protected static $interfaceClass = ConfigurationInterface::class;
+ protected static $exceptionClass = ConfigurationException::class;
+
+ /**
+ * Create a default config provider that first checks for environment
+ * variables, then checks for a specified profile in the environment-defined
+ * config file location (env variable is 'AWS_CONFIG_FILE', file location
+ * defaults to ~/.aws/config), then checks for the "default" profile in the
+ * environment-defined config file location, and failing those uses a default
+ * fallback set of configuration options.
+ *
+ * This provider is automatically wrapped in a memoize function that caches
+ * previously provided config options.
+ *
+ * @param array $config
+ *
+ * @return callable
+ */
+ public static function defaultProvider(array $config = [])
+ {
+ $configProviders = [self::env()];
+ if (
+ !isset($config['use_aws_shared_config_files'])
+ || $config['use_aws_shared_config_files'] != false
+ ) {
+ $configProviders[] = self::ini();
+ }
+ $configProviders[] = self::fallback();
+
+ $memo = self::memoize(
+ call_user_func_array([ConfigurationProvider::class, 'chain'], $configProviders)
+ );
+
+ if (isset($config['retries'])
+ && $config['retries'] instanceof CacheInterface
+ ) {
+ return self::cache($memo, $config['retries'], self::$cacheKey);
+ }
+
+ return $memo;
+ }
+
+ /**
+ * Provider that creates config from environment variables.
+ *
+ * @return callable
+ */
+ public static function env()
+ {
+ return function () {
+ // Use config from environment variables, if available
+ $mode = getenv(self::ENV_MODE);
+ $maxAttempts = getenv(self::ENV_MAX_ATTEMPTS)
+ ? getenv(self::ENV_MAX_ATTEMPTS)
+ : self::DEFAULT_MAX_ATTEMPTS;
+ if (!empty($mode)) {
+ return Promise\Create::promiseFor(
+ new Configuration($mode, $maxAttempts)
+ );
+ }
+
+ return self::reject('Could not find environment variable config'
+ . ' in ' . self::ENV_MODE);
+ };
+ }
+
+ /**
+ * Fallback config options when other sources are not set.
+ *
+ * @return callable
+ */
+ public static function fallback()
+ {
+ return function () {
+ return Promise\Create::promiseFor(
+ new Configuration(self::DEFAULT_MODE, self::DEFAULT_MAX_ATTEMPTS)
+ );
+ };
+ }
+
+ /**
+ * Config provider that creates config using a config file whose location
+ * is specified by an environment variable 'AWS_CONFIG_FILE', defaulting to
+ * ~/.aws/config if not specified
+ *
+ * @param string|null $profile Profile to use. If not specified will use
+ * the "default" profile.
+ * @param string|null $filename If provided, uses a custom filename rather
+ * than looking in the default directory.
+ *
+ * @return callable
+ */
+ public static function ini(
+ $profile = null,
+ $filename = null
+ ) {
+ $filename = $filename ?: (self::getDefaultConfigFilename());
+ $profile = $profile ?: (getenv(self::ENV_PROFILE) ?: 'default');
+
+ return function () use ($profile, $filename) {
+ if (!@is_readable($filename)) {
+ return self::reject("Cannot read configuration from $filename");
+ }
+ $data = \Aws\parse_ini_file($filename, true);
+ if ($data === false) {
+ return self::reject("Invalid config file: $filename");
+ }
+ if (!isset($data[$profile])) {
+ return self::reject("'$profile' not found in config file");
+ }
+ if (!isset($data[$profile][self::INI_MODE])) {
+ return self::reject("Required retry config values
+ not present in INI profile '{$profile}' ({$filename})");
+ }
+
+ $maxAttempts = isset($data[$profile][self::INI_MAX_ATTEMPTS])
+ ? $data[$profile][self::INI_MAX_ATTEMPTS]
+ : self::DEFAULT_MAX_ATTEMPTS;
+
+ return Promise\Create::promiseFor(
+ new Configuration(
+ $data[$profile][self::INI_MODE],
+ $maxAttempts
+ )
+ );
+ };
+ }
+
+ /**
+ * Unwraps a configuration object in whatever valid form it is in,
+ * always returning a ConfigurationInterface object.
+ *
+ * @param mixed $config
+ * @return ConfigurationInterface
+ * @throws \InvalidArgumentException
+ */
+ public static function unwrap($config)
+ {
+ if (is_callable($config)) {
+ $config = $config();
+ }
+ if ($config instanceof PromiseInterface) {
+ $config = $config->wait();
+ }
+ if ($config instanceof ConfigurationInterface) {
+ return $config;
+ }
+
+ // An integer value for this config indicates the legacy 'retries'
+ // config option, which is incremented to translate to max attempts
+ if (is_int($config)) {
+ return new Configuration('legacy', $config + 1);
+ }
+
+ if (is_array($config) && isset($config['mode'])) {
+ $maxAttempts = isset($config['max_attempts'])
+ ? $config['max_attempts']
+ : self::DEFAULT_MAX_ATTEMPTS;
+ return new Configuration($config['mode'], $maxAttempts);
+ }
+
+ throw new \InvalidArgumentException('Not a valid retry configuration'
+ . ' argument.');
+ }
+}
diff --git a/vendor/aws/aws-sdk-php/src/Retry/Exception/ConfigurationException.php b/vendor/aws/aws-sdk-php/src/Retry/Exception/ConfigurationException.php
new file mode 100644
index 0000000..0705c2e
--- /dev/null
+++ b/vendor/aws/aws-sdk-php/src/Retry/Exception/ConfigurationException.php
@@ -0,0 +1,14 @@
+<?php
+namespace Aws\Retry\Exception;
+
+use Aws\HasMonitoringEventsTrait;
+use Aws\MonitoringEventsInterface;
+
+/**
+ * Represents an error interacting with retry configuration
+ */
+class ConfigurationException extends \RuntimeException implements
+ MonitoringEventsInterface
+{
+ use HasMonitoringEventsTrait;
+}
diff --git a/vendor/aws/aws-sdk-php/src/Retry/QuotaManager.php b/vendor/aws/aws-sdk-php/src/Retry/QuotaManager.php
new file mode 100644
index 0000000..02e9fcd
--- /dev/null
+++ b/vendor/aws/aws-sdk-php/src/Retry/QuotaManager.php
@@ -0,0 +1,86 @@
+<?php
+namespace Aws\Retry;
+
+use Aws\Exception\AwsException;
+use Aws\ResultInterface;
+
+/**
+ * @internal
+ */
+class QuotaManager
+{
+ private $availableCapacity;
+ private $capacityAmount;
+ private $initialRetryTokens;
+ private $maxCapacity;
+ private $noRetryIncrement;
+ private $retryCost;
+ private $timeoutRetryCost;
+
+ public function __construct($config = [])
+ {
+ $this->initialRetryTokens = isset($config['initial_retry_tokens'])
+ ? $config['initial_retry_tokens']
+ : 500;
+ $this->noRetryIncrement = isset($config['no_retry_increment'])
+ ? $config['no_retry_increment']
+ : 1;
+ $this->retryCost = isset($config['retry_cost'])
+ ? $config['retry_cost']
+ : 5;
+ $this->timeoutRetryCost = isset($config['timeout_retry_cost'])
+ ? $config['timeout_retry_cost']
+ : 10;
+ $this->maxCapacity = $this->initialRetryTokens;
+ $this->availableCapacity = $this->initialRetryTokens;
+ }
+
+ public function hasRetryQuota($result)
+ {
+ if ($result instanceof AwsException && $result->isConnectionError()) {
+ $this->capacityAmount = $this->timeoutRetryCost;
+ } else {
+ $this->capacityAmount = $this->retryCost;
+ }
+
+ if ($this->capacityAmount > $this->availableCapacity) {
+ return false;
+ }
+
+ $this->availableCapacity -= $this->capacityAmount;
+ return true;
+ }
+
+ public function releaseToQuota($result)
+ {
+ if ($result instanceof AwsException) {
+ $statusCode = (int) $result->getStatusCode();
+ } elseif ($result instanceof ResultInterface) {
+ $statusCode = isset($result['@metadata']['statusCode'])
+ ? (int) $result['@metadata']['statusCode']
+ : null;
+ }
+
+ if (!empty($statusCode) && $statusCode >= 200 && $statusCode < 300) {
+ if (isset($this->capacityAmount)) {
+ $amount = $this->capacityAmount;
+ $this->availableCapacity += $amount;
+ unset($this->capacityAmount);
+ } else {
+ $amount = $this->noRetryIncrement;
+ $this->availableCapacity += $amount;
+ }
+ $this->availableCapacity = min(
+ $this->availableCapacity,
+ $this->maxCapacity
+ );
+ }
+
+ return (isset($amount) ? $amount : 0);
+ }
+
+ public function getAvailableCapacity()
+ {
+ return $this->availableCapacity;
+ }
+}
diff --git a/vendor/aws/aws-sdk-php/src/Retry/RateLimiter.php b/vendor/aws/aws-sdk-php/src/Retry/RateLimiter.php
new file mode 100644
index 0000000..b58cc59
--- /dev/null
+++ b/vendor/aws/aws-sdk-php/src/Retry/RateLimiter.php
@@ -0,0 +1,182 @@
+<?php
+namespace Aws\Retry;
+
+
+/**
+ * @internal
+ */
+class RateLimiter
+{
+ // User-configurable constants
+ private $beta;
+ private $minCapacity;
+ private $minFillRate;
+ private $scaleConstant;
+ private $smooth;
+
+ // Optional callable time provider
+ private $timeProvider;
+
+ // Pre-set state variables
+ private $currentCapacity = 0;
+ private $enabled = false;
+ private $lastMaxRate = 0;
+ private $measuredTxRate = 0;
+ private $requestCount = 0;
+
+ // Other state variables
+ private $fillRate;
+ private $lastThrottleTime;
+ private $lastTimestamp;
+ private $lastTxRateBucket;
+ private $maxCapacity;
+ private $timeWindow;
+
+ public function __construct($options = [])
+ {
+ $this->beta = isset($options['beta'])
+ ? $options['beta']
+ : 0.7;
+ $this->minCapacity = isset($options['min_capacity'])
+ ? $options['min_capacity']
+ : 1;
+ $this->minFillRate = isset($options['min_fill_rate'])
+ ? $options['min_fill_rate']
+ : 0.5;
+ $this->scaleConstant = isset($options['scale_constant'])
+ ? $options['scale_constant']
+ : 0.4;
+ $this->smooth = isset($options['smooth'])
+ ? $options['smooth']
+ : 0.8;
+ $this->timeProvider = isset($options['time_provider'])
+ ? $options['time_provider']
+ : null;
+
+ $this->lastTxRateBucket = floor($this->time());
+ $this->lastThrottleTime = $this->time();
+ }
+
+ public function isEnabled()
+ {
+ return $this->enabled;
+ }
+
+ public function getSendToken()
+ {
+ $this->acquireToken(1);
+ }
+
+ public function updateSendingRate($isThrottled)
+ {
+ $this->updateMeasuredRate();
+
+ if ($isThrottled) {
+ if (!$this->isEnabled()) {
+ $rateToUse = $this->measuredTxRate;
+ } else {
+ $rateToUse = min($this->measuredTxRate, $this->fillRate);
+ }
+
+ $this->lastMaxRate = $rateToUse;
+ $this->calculateTimeWindow();
+ $this->lastThrottleTime = $this->time();
+ $calculatedRate = $this->cubicThrottle($rateToUse);
+ $this->enableTokenBucket();
+ } else {
+ $this->calculateTimeWindow();
+ $calculatedRate = $this->cubicSuccess($this->time());
+ }
+ $newRate = min($calculatedRate, 2 * $this->measuredTxRate);
+ $this->updateTokenBucketRate($newRate);
+ return $newRate;
+ }
+
+ private function acquireToken($amount)
+ {
+ if (!$this->enabled) {
+ return true;
+ }
+
+ $this->refillTokenBucket();
+
+ if ($amount > $this->currentCapacity) {
+ usleep((int) (1000000 * ($amount - $this->currentCapacity) / $this->fillRate));
+ }
+
+ $this->currentCapacity -= $amount;
+ return true;
+ }
+
+ private function calculateTimeWindow()
+ {
+ $this->timeWindow = pow(($this->lastMaxRate * (1 - $this->beta) / $this->scaleConstant), 0.333);
+ }
+
+ private function cubicSuccess($timestamp)
+ {
+ $dt = $timestamp - $this->lastThrottleTime;
+ return $this->scaleConstant * pow($dt - $this->timeWindow, 3) + $this->lastMaxRate;
+ }
+
+ private function cubicThrottle($rateToUse)
+ {
+ return $rateToUse * $this->beta;
+ }
+
+ private function enableTokenBucket()
+ {
+ $this->enabled = true;
+ }
+
+ private function refillTokenBucket()
+ {
+ $timestamp = $this->time();
+ if (!isset($this->lastTimestamp)) {
+ $this->lastTimestamp = $timestamp;
+ return;
+ }
+ $fillAmount = ($timestamp - $this->lastTimestamp) * $this->fillRate;
+ $this->currentCapacity = $this->currentCapacity + $fillAmount;
+ if (!is_null($this->maxCapacity)) {
+ $this->currentCapacity = min(
+ $this->maxCapacity,
+ $this->currentCapacity
+ );
+ }
+
+ $this->lastTimestamp = $timestamp;
+ }
+
+ private function time()
+ {
+ if (is_callable($this->timeProvider)) {
+ $provider = $this->timeProvider;
+ $time = $provider();
+ return $time;
+ }
+ return microtime(true);
+ }
+
+ private function updateMeasuredRate()
+ {
+ $timestamp = $this->time();
+ $timeBucket = floor(round($timestamp, 3) * 2) / 2;
+ $this->requestCount++;
+ if ($timeBucket > $this->lastTxRateBucket) {
+ $currentRate = $this->requestCount / ($timeBucket - $this->lastTxRateBucket);
+ $this->measuredTxRate = ($currentRate * $this->smooth)
+ + ($this->measuredTxRate * (1 - $this->smooth));
+ $this->requestCount = 0;
+ $this->lastTxRateBucket = $timeBucket;
+ }
+ }
+
+ private function updateTokenBucketRate($newRps)
+ {
+ $this->refillTokenBucket();
+ $this->fillRate = max($newRps, $this->minFillRate);
+ $this->maxCapacity = max($newRps, $this->minCapacity);
+ $this->currentCapacity = min($this->currentCapacity, $this->maxCapacity);
+ }
+}
diff --git a/vendor/aws/aws-sdk-php/src/Retry/RetryHelperTrait.php b/vendor/aws/aws-sdk-php/src/Retry/RetryHelperTrait.php
new file mode 100644
index 0000000..a7edb72
--- /dev/null
+++ b/vendor/aws/aws-sdk-php/src/Retry/RetryHelperTrait.php
@@ -0,0 +1,56 @@
+<?php
+namespace Aws\Retry;
+
+use Aws\Exception\AwsException;
+use Aws\ResultInterface;
+
+trait RetryHelperTrait
+{
+ private function addRetryHeader($request, $retries, $delayBy)
+ {
+ return $request->withHeader('aws-sdk-retry', "{$retries}/{$delayBy}");
+ }
+
+
+ private function updateStats($retries, $delay, array &$stats)
+ {
+ if (!isset($stats['total_retry_delay'])) {
+ $stats['total_retry_delay'] = 0;
+ }
+
+ $stats['total_retry_delay'] += $delay;
+ $stats['retries_attempted'] = $retries;
+ }
+
+ private function updateHttpStats($value, array &$stats)
+ {
+ if (empty($stats['http'])) {
+ $stats['http'] = [];
+ }
+
+ if ($value instanceof AwsException) {
+ $resultStats = $value->getTransferInfo();
+ $stats['http'] []= $resultStats;
+ } elseif ($value instanceof ResultInterface) {
+ $resultStats = isset($value['@metadata']['transferStats']['http'][0])
+ ? $value['@metadata']['transferStats']['http'][0]
+ : [];
+ $stats['http'] []= $resultStats;
+ }
+ }
+
+ private function bindStatsToReturn($return, array $stats)
+ {
+ if ($return instanceof ResultInterface) {
+ if (!isset($return['@metadata'])) {
+ $return['@metadata'] = [];
+ }
+
+ $return['@metadata']['transferStats'] = $stats;
+ } elseif ($return instanceof AwsException) {
+ $return->setTransferInfo($stats);
+ }
+
+ return $return;
+ }
+}