Skip to content

Commit

Permalink
support doing exponential backoff in non-blocking mode in Swoole
Browse files Browse the repository at this point in the history
  • Loading branch information
deminy committed Aug 6, 2020
1 parent 1f70c18 commit 8cbaf54
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 4 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
Exponential back-offs prevent overloading an unavailable service by doubling the timeout each iteration. This class uses
an exponential back-off algorithm to calculate the timeout for the next request.

This library allows doing exponential backoff in non-blocking mode in [Swoole](https://github.com/swoole/swoole-src).

# Installation

```bash
Expand Down
4 changes: 4 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@
"require-dev": {
"crowdstar/reflection": "~1.0.0",
"phpunit/phpunit": "~7.0",
"swoole/ide-helper": "@dev",
"squizlabs/php_codesniffer": ">=2.0"
},
"suggest": {
"ext-swoole": "Allow to do exponential backoff in non-blocking mode in Swoole"
},
"autoload": {
"psr-4": {
"CrowdStar\\Backoff\\": "src"
Expand Down
39 changes: 35 additions & 4 deletions src/ExponentialBackoff.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
namespace CrowdStar\Backoff;

use Closure;
use Swoole\Coroutine;

/**
* Class ExponentialBackoff
Expand All @@ -35,11 +36,21 @@ class ExponentialBackoff
public const TYPE_MICROSECONDS = 1;
public const TYPE_SECONDS = 2;

protected const SAPI_DEFAULT = 1;
protected const SAPI_SWOOLE = 2;

/**
* @var int
*/
protected $type = self::TYPE_MICROSECONDS;

/**
* @var string
* @see \CrowdStar\Backoff\ExponentialBackoff::SAPI_DEFAULT
* @see \CrowdStar\Backoff\ExponentialBackoff::SAPI_SWOOLE
*/
protected $sapi;

/**
* @var int
*/
Expand All @@ -55,8 +66,10 @@ class ExponentialBackoff
*/
protected $retryCondition;

public function __construct(AbstractRetryCondition $retryCondition)
public function __construct(AbstractRetryCondition $retryCondition, int $sapi = 0)
{
$this->sapi = $sapi ?: (extension_loaded('swoole') ? self::SAPI_SWOOLE : self::SAPI_DEFAULT);

$this->setRetryCondition($retryCondition);
}

Expand Down Expand Up @@ -177,10 +190,28 @@ protected function sleep(): self
{
switch ($this->getType()) {
case self::TYPE_MICROSECONDS:
usleep($this->getTimeoutMicroseconds($this->getCurrentAttempts()));
$microSeconds = $this->getTimeoutMicroseconds($this->getCurrentAttempts());
switch ($this->sapi) {
case self::SAPI_SWOOLE:
// Minimum execution delay in Swoole is 1ms.
Coroutine::sleep(max($microSeconds / 1000000, 0.001));
break;
default:
usleep($microSeconds);
break;
}
break;
case self::TYPE_SECONDS:
usleep($this->getTimeoutSeconds($this->getCurrentAttempts()));
$seconds = $this->getTimeoutSeconds($this->getCurrentAttempts());
switch ($this->sapi) {
case self::SAPI_SWOOLE:
// Minimum execution delay in Swoole is 1ms.
Coroutine::sleep(max($seconds, 0.001));
break;
default:
sleep($seconds);
break;
}
break;
default:
throw new Exception("invalid backoff type '{$this->getType()}'");
Expand All @@ -194,7 +225,7 @@ protected function sleep(): self
*/
protected function getTimeoutSeconds(int $iteration, int $initialTimeout = 1): int
{
return ($this->getTimeoutMicroseconds($iteration, $initialTimeout * 1000000) / 1000000);
return (int) ($this->getTimeoutMicroseconds($iteration, $initialTimeout * 1000000) / 1000000);
}

/**
Expand Down

0 comments on commit 8cbaf54

Please sign in to comment.