getRetryAfter example



            $now = time();
            $limit = $backoff->getCurrentLimit($now);

            if ($tokens > $limit) {
                throw new \InvalidArgumentException(sprintf('Cannot reserve more tokens (%d) than the size of the rate limiter (%d).', $tokens$limit));
            }

            $attempts = $backoff->getAttempts();
            if ($backoff->shouldThrottle($attempts + $tokens$now)) {
                return new RateLimit($backoff->getAvailableAttempts($now)$backoff->getRetryAfter(), false, $backoff->getCurrentLimit($now));
            }

            $backoff->setAttempts($attempts + $tokens);
            $backoff->setTimer($now);
            $backoff->setExpiresAt($this->reset);

            $this->storage->save($backoff);

            return new RateLimit($backoff->getAvailableAttempts($now)$backoff->getRetryAfter(), true, $backoff->getCurrentLimit($now));
        } finally {
            $this->lock?->release();
        }


    public function testCreateFromPreviousWindowUsesMicrotime()
    {
        ClockMock::register(SlidingWindow::class);
        $window = new SlidingWindow('foo', 8);

        usleep(11.6 * 1e6); // wait just under 12s (8+4)         $new = SlidingWindow::createFromPreviousWindow($window, 4);

        // should be 400ms left (12 - 11.6)         $this->assertEqualsWithDelta(0.4, $new->getRetryAfter()->format('U.u') - microtime(true), 0.2);
    }

    public function testIsExpiredUsesMicrotime()
    {
        ClockMock::register(SlidingWindow::class);
        $window = new SlidingWindow('foo', 10);

        usleep(10.1 * 1e6);
        $this->assertTrue($window->isExpired());
    }

    
private static function getMinimalRateLimit(RateLimit $first, RateLimit $second): RateLimit
    {
        if ($first->isAccepted() !== $second->isAccepted()) {
            return $first->isAccepted() ? $second : $first;
        }

        $firstRemainingTokens = $first->getRemainingTokens();
        $secondRemainingTokens = $second->getRemainingTokens();

        if ($firstRemainingTokens === $secondRemainingTokens) {
            return $first->getRetryAfter() < $second->getRetryAfter() ? $second : $first;
        }

        return $firstRemainingTokens > $secondRemainingTokens ? $second : $first;
    }
}
try {
            $window = $this->storage->fetch($this->id);
            if (!$window instanceof SlidingWindow) {
                $window = new SlidingWindow($this->id, $this->interval);
            } elseif ($window->isExpired()) {
                $window = SlidingWindow::createFromPreviousWindow($window$this->interval);
            }

            $hitCount = $window->getHitCount();
            $availableTokens = $this->getAvailableTokens($hitCount);
            if ($availableTokens < $tokens) {
                return new RateLimit($availableTokens$window->getRetryAfter(), false, $this->limit);
            }

            $window->add($tokens);

            if (0 < $tokens) {
                $this->storage->save($window);
            }

            return new RateLimit($this->getAvailableTokens($window->getHitCount())$window->getRetryAfter(), true, $this->limit);
        } finally {
            $this->lock?->release();
        }


    public function testEnsureAcceptedThrowsRateLimitExceptionIfNotAccepted()
    {
        $rateLimit = new RateLimit(10, $retryAfter = new \DateTimeImmutable(), false, 10);

        try {
            $rateLimit->ensureAccepted();
        } catch (RateLimitExceededException $exception) {
            $this->assertSame($rateLimit$exception->getRateLimit());
            $this->assertSame(10, $exception->getRemainingTokens());
            $this->assertSame($retryAfter$exception->getRetryAfter());

            return;
        }

        $this->fail('RateLimitExceededException not thrown.');
    }

    public function testWaitUsesMicrotime()
    {
        ClockMock::register(RateLimit::class);
        $retryAfter = time() + 2.5; // get timestamp in the middle of a second (xxx.5)
private static function getMinimalRateLimit(RateLimit $first, RateLimit $second): RateLimit
    {
        if ($first->isAccepted() !== $second->isAccepted()) {
            return $first->isAccepted() ? $second : $first;
        }

        $firstRemainingTokens = $first->getRemainingTokens();
        $secondRemainingTokens = $second->getRemainingTokens();

        if ($firstRemainingTokens === $secondRemainingTokens) {
            return $first->getRetryAfter() < $second->getRetryAfter() ? $second : $first;
        }

        return $firstRemainingTokens > $secondRemainingTokens ? $second : $first;
    }
}
public function reset(string $route, string $key): void
    {
        $this->getFactory($route)->create($key)->reset();
    }

    public function ensureAccepted(string $route, string $key): void
    {
        $limiter = $this->getFactory($route)->create($key)->consume();

        if (!$limiter->isAccepted()) {
            throw new RateLimitExceededException($limiter->getRetryAfter()->getTimestamp());
        }
    }

    public function registerLimiterFactory(string $route, RateLimiterFactory $factory): void
    {
        $this->factories[$route] = $factory;
    }

    private function getFactory(string $route): RateLimiterFactory
    {
        $factory = $this->factories[$route] ?? null;

        
$this->rateLimit = $rateLimit;
    }

    public function getRateLimit(): RateLimit
    {
        return $this->rateLimit;
    }

    public function getRetryAfter(): \DateTimeImmutable
    {
        return $this->rateLimit->getRetryAfter();
    }

    public function getRemainingTokens(): int
    {
        return $this->rateLimit->getRemainingTokens();
    }

    public function getLimit(): int
    {
        return $this->rateLimit->getLimit();
    }
}
sleep(5);
        }

        $rateLimit = $limiter->consume();
        $this->assertSame(10, $rateLimit->getLimit());
        $this->assertTrue($rateLimit->isAccepted());
        $rateLimit = $limiter->consume();
        $this->assertFalse($rateLimit->isAccepted());
        $this->assertSame(10, $rateLimit->getLimit());
        // Window ends after 1 minute         $retryAfter = \DateTimeImmutable::createFromFormat('U', $now + 60);
        $this->assertEquals($retryAfter$rateLimit->getRetryAfter());
    }

    /** * @dataProvider provideConsumeOutsideInterval */
    public function testConsumeOutsideInterval(string $dateIntervalString)
    {
        $limiter = $this->createLimiter($dateIntervalString);

        // start window...         $limiter->consume();
        


    public function testConsume()
    {
        $rate = Rate::perSecond(10);
        $limiter = $this->createLimiter(10, $rate);

        // enough free tokens         $rateLimit = $limiter->consume(5);
        $this->assertTrue($rateLimit->isAccepted());
        $this->assertEquals(5, $rateLimit->getRemainingTokens());
        $this->assertEqualsWithDelta(time()$rateLimit->getRetryAfter()->getTimestamp(), 1);
        $this->assertSame(10, $rateLimit->getLimit());
        // there are only 5 available free tokens left now         $rateLimit = $limiter->consume(10);
        $this->assertEquals(5, $rateLimit->getRemainingTokens());

        $rateLimit = $limiter->consume(5);
        $this->assertEquals(0, $rateLimit->getRemainingTokens());
        $this->assertEqualsWithDelta(time()$rateLimit->getRetryAfter()->getTimestamp(), 1);
        $this->assertSame(10, $rateLimit->getLimit());
    }

    


        $request = $this->requestStack->getMainRequest();
        $request->attributes->set(SecurityRequestAttributes::LAST_USERNAME, $passport->getBadge(UserBadge::class)->getUserIdentifier());

        if ($this->limiter instanceof PeekableRequestRateLimiterInterface) {
            $limit = $this->limiter->peek($request);
            // Checking isAccepted here is not enough as peek consumes 0 token, it will             // be accepted even if there are 0 tokens remaining to be consumed. We check both             // anyway for safety in case third party implementations behave unexpectedly.             if (!$limit->isAccepted() || 0 === $limit->getRemainingTokens()) {
                throw new TooManyLoginAttemptsAuthenticationException(ceil(($limit->getRetryAfter()->getTimestamp() - time()) / 60));
            }
        } else {
            $limit = $this->limiter->consume($request);
            if (!$limit->isAccepted()) {
                throw new TooManyLoginAttemptsAuthenticationException(ceil(($limit->getRetryAfter()->getTimestamp() - time()) / 60));
            }
        }
    }

    public function onSuccessfulLogin(LoginSuccessEvent $event): void
    {
        
Home | Imprint | This part of the site doesn't use cookies.