From b36aaa07dde7ed6a62471ae539ea5f1023b3aedd Mon Sep 17 00:00:00 2001 From: Stephan Groen Date: Wed, 20 Oct 2021 12:07:23 +0200 Subject: [PATCH 1/2] Add basic rate limit sleep support --- README.md | 5 ++++ composer.json | 3 ++- src/Picqer/Financials/Exact/Connection.php | 29 ++++++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2782f25e..6406437a 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,11 @@ $connection->getMinutelyLimitReset(); // Retrieve the timestamp for when the min ``` _Do note when you have no more minutely calls available, Exact only sends the Minutely Limit headers. So in that case, the Daily Limit headers will remain 0 until the minutely reset rolls over._ +There is basic support to `sleep` upon hitting the minutely rate limits. If you enable "Wait on minutely rate limit hit", the client will sleep until the limit is reset. Daily limits are not considered. + +```php +$connection->setWaitOnMinutelyRateLimitHit(true); +``` ### Use the library to do stuff (examples) diff --git a/composer.json b/composer.json index 2b5f4faa..d249d293 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,8 @@ ], "require": { "php": ">=7.2.0", - "guzzlehttp/guzzle": "~6.0|~7.0" + "guzzlehttp/guzzle": "~6.0|~7.0", + "ext-json": "*" }, "require-dev": { "phpunit/phpunit": "^8.5|^9.3" diff --git a/src/Picqer/Financials/Exact/Connection.php b/src/Picqer/Financials/Exact/Connection.php index 5fc6024b..b6605b60 100644 --- a/src/Picqer/Financials/Exact/Connection.php +++ b/src/Picqer/Financials/Exact/Connection.php @@ -140,6 +140,11 @@ class Connection */ protected $minutelyLimitReset; + /** + * @var bool + */ + private $waitOnMinutelyRateLimitHit = false; + /** * @return Client */ @@ -266,6 +271,7 @@ private function createRequest($method, $endpoint, $body = null, array $params = */ public function get($url, array $params = [], array $headers = []) { + $this->waitIfMinutelyRateLimitHit(); $url = $this->formatUrl($url, $url !== 'current/Me', $url == $this->nextUrl); try { @@ -289,6 +295,7 @@ public function get($url, array $params = [], array $headers = []) */ public function post($url, $body) { + $this->waitIfMinutelyRateLimitHit(); $url = $this->formatUrl($url); try { @@ -334,6 +341,7 @@ public function upload($topic, $body) */ public function put($url, $body) { + $this->waitIfMinutelyRateLimitHit(); $url = $this->formatUrl($url); try { @@ -356,6 +364,7 @@ public function put($url, $body) */ public function delete($url) { + $this->waitIfMinutelyRateLimitHit(); $url = $this->formatUrl($url); try { @@ -870,4 +879,24 @@ private function extractRateLimits(Response $response) $this->minutelyLimitRemaining = (int) $response->getHeaderLine('X-RateLimit-Minutely-Remaining'); $this->minutelyLimitReset = (int) $response->getHeaderLine('X-RateLimit-Minutely-Reset'); } + + protected function waitIfMinutelyRateLimitHit() + { + if (! $this->waitOnMinutelyRateLimitHit) { + return; + } + + $minutelyReset = $this->getMinutelyLimitReset(); + + if ($this->getMinutelyLimitRemaining() === 0 && $minutelyReset) { + // add a second for rounding differences + $resetsInSeconds = (($minutelyReset / 1000) - time()) + 1; + sleep($resetsInSeconds); + } + } + + public function setWaitOnMinutelyRateLimitHit(bool $waitOnMinutelyRateLimitHit) + { + $this->waitOnMinutelyRateLimitHit = $waitOnMinutelyRateLimitHit; + } } From 45e476b214959e8fa710d40b017d30cac18503ff Mon Sep 17 00:00:00 2001 From: Stephan Groen Date: Wed, 20 Oct 2021 12:10:02 +0200 Subject: [PATCH 2/2] Update Connection.php --- src/Picqer/Financials/Exact/Connection.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Picqer/Financials/Exact/Connection.php b/src/Picqer/Financials/Exact/Connection.php index b6605b60..e91f007b 100644 --- a/src/Picqer/Financials/Exact/Connection.php +++ b/src/Picqer/Financials/Exact/Connection.php @@ -885,9 +885,9 @@ protected function waitIfMinutelyRateLimitHit() if (! $this->waitOnMinutelyRateLimitHit) { return; } - + $minutelyReset = $this->getMinutelyLimitReset(); - + if ($this->getMinutelyLimitRemaining() === 0 && $minutelyReset) { // add a second for rounding differences $resetsInSeconds = (($minutelyReset / 1000) - time()) + 1;