$bucket =
$this->storage->
fetch($this->id
);
if (!
$bucket instanceof TokenBucket
) { $bucket =
new TokenBucket($this->id,
$this->maxBurst,
$this->rate
);
} $now =
microtime(true
);
$availableTokens =
$bucket->
getAvailableTokens($now);
if ($availableTokens >=
max(1,
$tokens)) { // tokens are now available, update bucket
$bucket->
setTokens($availableTokens -
$tokens);
$bucket->
setTimer($now);
$reservation =
new Reservation($now,
new RateLimit($bucket->
getAvailableTokens($now), \DateTimeImmutable::
createFromFormat('U',
floor($now)), true,
$this->maxBurst
));
} else { $remainingTokens =
$tokens -
$availableTokens;
$waitDuration =
$this->rate->
calculateTimeForTokens($remainingTokens);
if (null !==
$maxTime &&
$waitDuration >
$maxTime) { // process needs to wait longer than set interval
$rateLimit =
new RateLimit($availableTokens, \DateTimeImmutable::
createFromFormat('U',
floor($now +
$waitDuration)), false,
$this->maxBurst
);
throw new MaxWaitDurationExceededException(sprintf('The rate limiter wait time ("%d" seconds) is longer than the provided maximum time ("%d" seconds).',
$waitDuration,
$maxTime),
$rateLimit);
}