mirror of
https://github.com/SociallyDev/Spaces-API.git
synced 2025-08-14 02:27:23 -07:00
v2: Updates
* Simplifies & beautifies everything * Introduces a new Class system. * Errors are defaulted to AWS's handler. * New function names & more efficient handling. * Should fix a majority of the errors. Please read the README for more!
This commit is contained in:
parent
ad0726e41e
commit
e6d7753dc8
1095 changed files with 45088 additions and 2911 deletions
182
aws/Aws/Retry/RateLimiter.php
Normal file
182
aws/Aws/Retry/RateLimiter.php
Normal file
|
@ -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(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);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue