Skip to content

Commit

Permalink
Implement Exponential retry policy
Browse files Browse the repository at this point in the history
  • Loading branch information
ksaveras committed Dec 17, 2020
1 parent 6fb2365 commit 7b3533a
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 0 deletions.
56 changes: 56 additions & 0 deletions src/Policy/ExponentialRetryPolicy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php declare(strict_types=1);
/*
* This file is part of ksaveras/circuit-breaker.
*
* (c) Ksaveras Sakys <xawiers@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Ksaveras\CircuitBreaker\Policy;

use Ksaveras\CircuitBreaker\Circuit;

class ExponentialRetryPolicy implements RetryPolicyInterface
{
/**
* @var int
*/
private $initialTimeout;

/**
* @var int
*/
private $base;

/**
* @var int
*/
private $maximum;

public function __construct(int $initialTimeout = 600, int $maximum = 86400, int $base = 2)
{
if ($initialTimeout < 0) {
throw new \InvalidArgumentException('Initial timeout can not be negative number.');
}

if ($base <= 1) {
throw new \InvalidArgumentException('Base value must be greater than 1.');
}

if ($maximum <= 0 || $initialTimeout > $maximum) {
throw new \InvalidArgumentException('Maximum timeout must be positive and greater than initial timeout.');
}

$this->initialTimeout = $initialTimeout;
$this->base = $base;
$this->maximum = $maximum;
}

public function calculate(Circuit $circuit): int
{
$retries = max(0, $circuit->getFailureCount() - $circuit->getFailureThreshold());

return min($this->maximum, $this->base ** $retries + $this->initialTimeout);
}
}
89 changes: 89 additions & 0 deletions tests/Policy/ExponentialRetryPolicyTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php declare(strict_types=1);

namespace Ksaveras\CircuitBreaker\Tests\Policy;

use Ksaveras\CircuitBreaker\Policy\ExponentialRetryPolicy;
use Ksaveras\CircuitBreaker\Policy\LinearRetryPolicy;
use Ksaveras\CircuitBreaker\Tests\Fixture\CircuitBuilder;
use PHPUnit\Framework\TestCase;

class ExponentialRetryPolicyTest extends TestCase
{
public function testNegativeInitialTimeout(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Initial timeout can not be negative number.');

new ExponentialRetryPolicy(-1, 10);
}

public function testInvalidBaseValue(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Base value must be greater than 1.');

new ExponentialRetryPolicy(1, 10, 0);
}

public function testNegativeMaximumTimeoutValue(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Maximum timeout must be positive and greater than initial timeout.');

new ExponentialRetryPolicy(1, -1);
}

public function testInvalidMaximumTimeoutValue(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Maximum timeout must be positive and greater than initial timeout.');

new ExponentialRetryPolicy(10, 2);
}

public function testCalculateRetryTtl(): void
{
$policy = new ExponentialRetryPolicy(0);
$circuit = CircuitBuilder::builder()
->withFailureCount(2)
->withFailureThreshold(2)
->build();

self::assertEquals(1, $policy->calculate($circuit));

$circuit->increaseFailure();

self::assertEquals(2, $policy->calculate($circuit));

$circuit->increaseFailure();

self::assertEquals(4, $policy->calculate($circuit));

$circuit->increaseFailure();

self::assertEquals(8, $policy->calculate($circuit));
}

public function testCalculateMaximumRetryTtl(): void
{
$policy = new ExponentialRetryPolicy(0, 50);
$circuit = CircuitBuilder::builder()
->withFailureCount(6)
->withFailureThreshold(2)
->build();

self::assertEquals(16, $policy->calculate($circuit));

$circuit->increaseFailure();

self::assertEquals(32, $policy->calculate($circuit));

$circuit->increaseFailure();

self::assertEquals(50, $policy->calculate($circuit));

$circuit->increaseFailure();

self::assertEquals(50, $policy->calculate($circuit));
}
}

0 comments on commit 7b3533a

Please sign in to comment.