Skip to content

Commit 725165c

Browse files
Big-SharkMaxim Solovev
and
Maxim Solovev
authored
Add token price and maxTime parameters (#4)
* Add token price and maxTime parameters --------- Co-authored-by: Maxim Solovev <[email protected]>
1 parent 93ead07 commit 725165c

File tree

2 files changed

+68
-2
lines changed

2 files changed

+68
-2
lines changed

Diff for: src/ThrottlePlugin.php

+20-2
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,39 @@
66

77
use Http\Client\Common\Plugin;
88
use Http\Promise\Promise;
9+
use InvalidArgumentException;
910
use Psr\Http\Message\RequestInterface;
11+
use Symfony\Component\RateLimiter\Exception\MaxWaitDurationExceededException;
12+
use Symfony\Component\RateLimiter\Exception\ReserveNotSupportedException;
1013
use Symfony\Component\RateLimiter\LimiterInterface;
1114

1215
final class ThrottlePlugin implements Plugin
1316
{
1417
private LimiterInterface $rateLimiter;
1518

16-
public function __construct(LimiterInterface $rateLimiter)
19+
private int $tokens;
20+
21+
private ?float $maxTime;
22+
23+
/**
24+
* @param int $tokens the number of tokens required
25+
* @param float|null $maxTime maximum accepted waiting time in seconds
26+
*/
27+
public function __construct(LimiterInterface $rateLimiter, int $tokens = 1, ?float $maxTime = null)
1728
{
1829
$this->rateLimiter = $rateLimiter;
30+
$this->tokens = $tokens;
31+
$this->maxTime = $maxTime;
1932
}
2033

34+
/**
35+
* @throws MaxWaitDurationExceededException if $maxTime is set and the process needs to wait longer than its value (in seconds)
36+
* @throws ReserveNotSupportedException if this limiter implementation doesn't support reserving tokens
37+
* @throws InvalidArgumentException if $tokens is larger than the maximum burst size
38+
*/
2139
public function handleRequest(RequestInterface $request, callable $next, callable $first): Promise
2240
{
23-
$this->rateLimiter->reserve()->wait();
41+
$this->rateLimiter->reserve($this->tokens, $this->maxTime)->wait();
2442

2543
return $next($request);
2644
}

Diff for: tests/ThrottlePluginTest.php

+48
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Nyholm\Psr7\Request;
1212
use PHPUnit\Framework\TestCase;
1313
use Symfony\Bridge\PhpUnit\ClockMock;
14+
use Symfony\Component\RateLimiter\Exception\MaxWaitDurationExceededException;
1415
use Symfony\Component\RateLimiter\RateLimit;
1516
use Symfony\Component\RateLimiter\RateLimiterFactory;
1617
use Symfony\Component\RateLimiter\Storage\InMemoryStorage;
@@ -56,4 +57,51 @@ public function testThrottle(): void
5657
$this->client->sendRequest(new Request('GET', ''));
5758
$this->assertEqualsWithDelta($timeAfterThrottle, time(), 1);
5859
}
60+
61+
public function testTokens(): void
62+
{
63+
$this->client = new PluginClient($this->mockClient, [
64+
new ThrottlePlugin(
65+
(new RateLimiterFactory(
66+
['id' => 'foo', 'policy' => 'fixed_window', 'limit' => 2, 'interval' => '3 seconds'],
67+
new InMemoryStorage(),
68+
))->create(),
69+
2,
70+
),
71+
]);
72+
73+
$time = time();
74+
$this->client->sendRequest(new Request('GET', ''));
75+
$this->client->sendRequest(new Request('GET', ''));
76+
$this->assertEqualsWithDelta($time, ($timeAfterThrottle = time()) - 3, 1);
77+
78+
$this->client->sendRequest(new Request('GET', ''));
79+
$this->assertEqualsWithDelta($timeAfterThrottle, time(), 1);
80+
}
81+
82+
public function testMaxTime(): void
83+
{
84+
$this->client = new PluginClient($this->mockClient, [
85+
new ThrottlePlugin(
86+
$rateLimit = (new RateLimiterFactory(
87+
['id' => 'foo', 'policy' => 'fixed_window', 'limit' => 2, 'interval' => '3 seconds'],
88+
new InMemoryStorage(),
89+
))->create(),
90+
1,
91+
1,
92+
),
93+
]);
94+
95+
$this->expectException(MaxWaitDurationExceededException::class);
96+
$this->expectExceptionMessage('The rate limiter wait time ("3" seconds) is longer than the provided maximum time ("1" seconds).');
97+
98+
$time = time();
99+
$this->client->sendRequest(new Request('GET', ''));
100+
$this->client->sendRequest(new Request('GET', ''));
101+
$this->client->sendRequest(new Request('GET', ''));
102+
$this->assertEqualsWithDelta($time, ($timeAfterThrottle = time()) - 3, 1);
103+
104+
$this->client->sendRequest(new Request('GET', ''));
105+
$this->assertEqualsWithDelta($timeAfterThrottle, time(), 1);
106+
}
59107
}

0 commit comments

Comments
 (0)