Skip to content

Commit

Permalink
Implemented minutely rate limit with pause
Browse files Browse the repository at this point in the history
  • Loading branch information
Joost van der Meijden committed Mar 29, 2019
1 parent 28ec876 commit e0bda2e
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 18 deletions.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
],
"require": {
"php": ">=5.5.0",
"guzzlehttp/guzzle": "~6.0"
"guzzlehttp/guzzle": "~6.0",
"ext-json": "*"
},
"require-dev": {
"phpunit/phpunit": "~4.8.35"
Expand Down
174 changes: 157 additions & 17 deletions src/Picqer/Financials/Exact/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@
*/
class Connection
{

/**
* Limit of calls per minute.
*/
const CALLS_LIMIT_PER_MINUTE = 60;

/**
* @var string
*/
Expand Down Expand Up @@ -67,6 +73,36 @@ class Connection
* @var mixed
*/
private $refreshToken;

/**
* @var bool Pauses a request to make sure the calls per minute restriction is respected.
*/
private $pauseForMinuteLimit = false;

/**
* @var bool Pauses a request to make sure the calls are not made during maintenance.
*/
private $pauseForMaintenance = false;

/**
* @var int
*/
private $callsLimit = self::CALLS_LIMIT_PER_MINUTE;

/**
* @var int
*/
private $callsLeft = self::CALLS_LIMIT_PER_MINUTE;

/**
* @var array Start time of the maintenance in array format [H, m, i].
*/
private $startMaintenance = [4, 0, 0];

/**
* @var array End time of the maintenance in array format [H, m, i].
*/
private $endMaintenance = [4, 30, 0];

/**
* @var mixed
Expand Down Expand Up @@ -152,6 +188,90 @@ public function connect()

return $client;
}

/**
* @return bool
*/
public function pauseForMinuteLimitEnabled()
{
return $this->pauseForMinuteLimit;
}

/**
* @return self
*/
public function enablePauseForMinuteLimit()
{
$this->pauseForMinuteLimit = true;
return $this;
}

/**
* @return self
*/
public function disablePauseForMinuteLimit()
{
$this->pauseForMinuteLimit = true;
return $this;
}

/**
* @return bool
*/
public function pauseForMaintenanceEnabled()
{
return $this->pauseForMaintenance;
}

/**
* @return self
*/
public function enablePauseForMaintenance()
{
$this->pauseForMaintenance = true;
return $this;
}

/**
* @return self
*/
public function disablePauseForMaintenance()
{
$this->pauseForMaintenance = false;
return $this;
}

/**
* Pauses the process until time limit is over
*/
private function pause()
{
if ($this->pauseForMinuteLimitEnabled()) {
// take 90% of callsLimit so we have some tolerance when multiple process are running
if($this->callsLeft <= ($this->callsLimit * 0.10)) {
sleep(60);
}
}

if ($this->pauseForMaintenanceEnabled()) {
$startMaintenance = mktime(
$this->startMaintenance[0],
$this->startMaintenance[1],
$this->startMaintenance[2]
);

$endMaintenance = mktime(
$this->endMaintenance[0],
$this->endMaintenance[1],
$this->endMaintenance[2]
);

$now = time();
if ($now >= $startMaintenance && $now <= $endMaintenance) {
sleep($endMaintenance - $now);
}
}
}

/**
* @param string $method
Expand Down Expand Up @@ -192,15 +312,19 @@ private function createRequest($method = 'GET', $endpoint, $body = null, array $
}

/**
* @param string $url
* @param $url
* @param array $params
* @param array $headers
* @return mixed
* @throws ApiException
*
* @return mixed|null
* @throws \GuzzleHttp\Exception\GuzzleException
* @throws \Picqer\Financials\Exact\ApiException
*/
public function get($url, array $params = [], array $headers = [])
{
$url = $this->formatUrl($url, $url !== 'current/Me', $url == $this->nextUrl);

$this->pause();

try {
$request = $this->createRequest('GET', $url, null, $params, $headers);
Expand All @@ -213,16 +337,20 @@ public function get($url, array $params = [], array $headers = [])

return null;
}

/**
* @param string $url
* @param mixed $body
* @return mixed
* @throws ApiException
* @param $url
* @param $body
*
* @return mixed|null
* @throws \GuzzleHttp\Exception\GuzzleException
* @throws \Picqer\Financials\Exact\ApiException
*/
public function post($url, $body)
{
$url = $this->formatUrl($url);

$this->pause();

try {
$request = $this->createRequest('POST', $url, $body);
Expand All @@ -235,16 +363,20 @@ public function post($url, $body)

return null;
}

/**
* @param string $url
* @param mixed $body
* @return mixed
* @throws ApiException
* @param $url
* @param $body
*
* @return mixed|null
* @throws \GuzzleHttp\Exception\GuzzleException
* @throws \Picqer\Financials\Exact\ApiException
*/
public function put($url, $body)
{
$url = $this->formatUrl($url);

$this->pause();

try {
$request = $this->createRequest('PUT', $url, $body);
Expand All @@ -257,15 +389,19 @@ public function put($url, $body)

return null;
}

/**
* @param string $url
* @return mixed
* @throws ApiException
* @param $url
*
* @return mixed|null
* @throws \GuzzleHttp\Exception\GuzzleException
* @throws \Picqer\Financials\Exact\ApiException
*/
public function delete($url)
{
$url = $this->formatUrl($url);

$this->pause();

try {
$request = $this->createRequest('DELETE', $url);
Expand Down Expand Up @@ -366,6 +502,10 @@ public function needsAuthentication()
private function parseResponse(Response $response, $returnSingleIfPossible = true)
{
try {
$this->callsLimit = (int) $response->getHeaderLine('X-RateLimit-Minutely-Limit');
$this->callsLeft = (int) $response->getHeaderLine('X-RateLimit-Minutely-Remaining');

$this->pause();

if ($response->getStatusCode() === 204) {
return [];
Expand Down

0 comments on commit e0bda2e

Please sign in to comment.