Skip to content

Commit 490b023

Browse files
committed
Improves rate limit handling and configuration
Refines logic for configuring wait mode via environment variable, ensuring consistent behavior when rate limits are exceeded. Updates documentation for clearer usage guidance. Enhances RateLimiter comments for maintainability and replaces generic exceptions with a specific exception type for day window.
1 parent 49e9e15 commit 490b023

6 files changed

Lines changed: 54 additions & 17 deletions

File tree

.openapi-generator/templates/ApiClient.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ class ApiClient extends \GuzzleHttp\Client
118118
$limitStore = new RateLimit\JsonRateLimitStore($path);
119119
}
120120

121-
$waitMode = $config['rate_limit_wait'] ?? true;
121+
$waitMode = $config['rate_limit_wait'] ?? (strtolower(\Ease\Shared::cfg('RBAPI_RATE_WAIT_MODE', 'false')) === 'true');
122122
$this->rateLimiter = new RateLimiter($limitStore, $waitMode);
123123

124124
parent::__construct($config);

.openapi-generator/templates/README.mustache

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ API_DEBUG=True
6060

6161
Set the `RBAPI_RATE_LIMIT_JSON_FILE` to override default /tmp/rbczpremiumapi_rates.json
6262

63+
When the `RBAPI_RATE_WAIT_MODE` is not set, the RateLimitExceededException is throwed. The 'true' value wait till the next day, to continue.
64+
65+
6366
Please follow the [installation procedure](#installation--usage) and then run the following:
6467

6568
```php

.openapi-generator/templates/RateLimiter.mustache

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,53 @@
11
<?php
22

3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of the MultiFlexi package
7+
*
8+
* https://github.com/VitexSoftware/php-vitexsoftware-rbczpremiumapi
9+
*
10+
* (c) Vítězslav Dvořák <http://vitexsoftware.com>
11+
*
12+
* For the full copyright and license information, please view the LICENSE
13+
* file that was distributed with this source code.
14+
*/
15+
316
namespace VitexSoftware\Raiffeisenbank\RateLimit;
417

518
class RateLimiter
619
{
720
private RateLimitStoreInterface $store;
821
private bool $waitMode;
922
23+
/**
24+
* Create a RateLimiter configured with a storage backend and a handling mode for exceeded limits.
25+
*
26+
* @param RateLimitStoreInterface $store storage backend for per-client rate-limit state
27+
* @param bool $waitMode if true, the limiter will wait until the limit window resets; if false, it will throw a RateLimitExceededException when limits are exceeded
28+
*/
1029
public function __construct(RateLimitStoreInterface $store, bool $waitMode = true)
1130
{
1231
$this->store = $store;
1332
$this->waitMode = $waitMode;
1433
}
34+
/**
35+
* Indicates whether the limiter is configured to wait when a rate limit is exceeded.
36+
*
37+
* @return bool `true` if the limiter waits until the rate-limit window expires, `false` otherwise
38+
*/
1539
public function isWaitMode(): bool
1640
{
1741
return $this->waitMode;
1842
}
1943

2044
/**
21-
* clientId = fingerprint of the certificate (sha1, serial+issuer, etc.)
22-
* secondLimits/dayLimits are obtained from API response headers.
45+
* Stores remaining rate-limit counts for a client for both the one-second and 24-hour windows.
46+
*
47+
* @param string $clientId Fingerprint identifying the client (e.g., certificate SHA1, serial+issuer).
48+
* @param int $remainingSecond remaining requests in the current one-second window
49+
* @param int $remainingDay remaining requests in the current 24-hour window
50+
* @param int $timestamp UNIX timestamp (seconds) when the limits were observed
2351
*/
2452
public function handleRateLimits(
2553
string $clientId,
@@ -32,7 +60,14 @@ class RateLimiter
3260
}
3361

3462
/**
35-
* Verification before the next request.
63+
* Ensures the client is allowed to make the next request by enforcing per-second and per-day rate limits.
64+
*
65+
* If a window is exhausted and wait mode is enabled, pauses execution for the required seconds to clear the window;
66+
* otherwise throws a RateLimitExceededException.
67+
*
68+
* @param string $clientId identifier of the client whose rate limits are checked
69+
*
70+
* @throws RateLimitExceededException if a rate limit is exceeded and wait mode is disabled
3671
*/
3772
public function checkBeforeRequest(string $clientId): void
3873
{
@@ -44,23 +79,23 @@ class RateLimiter
4479
// second window
4580
if ($second && $second['remaining'] <= 0) {
4681
$wait = max(0, 1 - ($now - $second['timestamp']));
82+
4783
if ($wait > 0) {
48-
if ($this->waitMode) {
49-
usleep($wait * 1_000_000);
50-
} else {
51-
throw new \Exception('Rate-limit (second window) exceeded');
52-
}
84+
error_log(sprintf('Rate-limit (second window) exceeded. Waiting %d seconds', $wait));
85+
usleep($wait * 1_000_000);
5386
}
5487
}
5588

5689
// day window
5790
if ($day && $day['remaining'] <= 0) {
5891
$wait = max(0, 86400 - ($now - $day['timestamp']));
92+
5993
if ($wait > 0) {
6094
if ($this->waitMode) {
95+
error_log(sprintf('Rate-limit (day window) exceeded. Waiting %d seconds', $wait));
6196
sleep($wait);
6297
} else {
63-
throw new \Exception('Rate-limit (day window) exceeded');
98+
throw new RateLimitExceededException('Rate-limit (day window) exceeded');
6499
}
65100
}
66101
}

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ API_DEBUG=True
5757

5858
Set the `RBAPI_RATE_LIMIT_JSON_FILE` to override default /tmp/rbczpremiumapi_rates.json
5959

60+
When the `RBAPI_RATE_WAIT_MODE` is not set, the RateLimitExceededException is throwed. The 'true' value wait till the next day, to continue.
61+
62+
6063
Please follow the [installation procedure](#installation--usage) and then run the following:
6164

6265
```php

lib/ApiClient.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ public function __construct(array $config = [])
118118
$limitStore = new RateLimit\JsonRateLimitStore($path);
119119
}
120120

121-
$waitMode = $config['rate_limit_wait'] ?? true;
121+
$waitMode = $config['rate_limit_wait'] ?? (strtolower(\Ease\Shared::cfg('RBAPI_RATE_WAIT_MODE', 'false')) === 'true');
122122
$this->rateLimiter = new RateLimiter($limitStore, $waitMode);
123123

124124
parent::__construct($config);

lib/RateLimit/RateLimiter.php

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,8 @@ public function checkBeforeRequest(string $clientId): void
8181
$wait = max(0, 1 - ($now - $second['timestamp']));
8282

8383
if ($wait > 0) {
84-
if ($this->waitMode) {
85-
error_log(sprintf('Rate-limit (second window) exceeded. Waiting %d seconds', $wait));
86-
usleep($wait * 1_000_000);
87-
} else {
88-
throw new RateLimitExceededException('Rate-limit (second window) exceeded');
89-
}
84+
error_log(sprintf('Rate-limit (second window) exceeded. Waiting %d seconds', $wait));
85+
usleep($wait * 1_000_000);
9086
}
9187
}
9288

0 commit comments

Comments
 (0)