Skip to content

Commit

Permalink
LinearBackOffPolicy has been added
Browse files Browse the repository at this point in the history
  • Loading branch information
vkartaviy committed May 6, 2015
1 parent 42a4eef commit 8d72645
Show file tree
Hide file tree
Showing 4 changed files with 303 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/Retry/BackOff/ExponentialBackOffPolicy.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use Retry\RetryContextInterface;

/**
* Implementation of {@link BackOffPolicyInterface} that increases the back-off period for each retry attempt in a given set.
* Implementation of {@link BackOffPolicyInterface} that exponentially increases the back-off period for each retry attempt in a given set.
*/
class ExponentialBackOffPolicy extends AbstractBackOffPolicy
{
Expand Down
54 changes: 54 additions & 0 deletions src/Retry/BackOff/LinearBackOffContext.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

namespace Retry\BackOff;

class LinearBackOffContext implements BackOffContextInterface
{
private $seed;
private $delta;
private $max;

private $interval;

public function __construct($seed, $delta, $max)
{
$this->seed = max(1, (int) $seed);
$this->delta = max(1, (int) $delta);
$this->max = max(1, (int) $max);

$this->interval = $this->seed;
}

public function getIntervalAndIncrement()
{
$interval = $this->interval;

if ($interval > $this->max) {
$interval = $this->max;
} else {
$this->interval = $this->getNextInterval();
}

return $interval;
}

public function getInterval()
{
return $this->interval;
}

public function resetInterval()
{
$this->interval = $this->seed;
}

public function getNextInterval()
{
return $this->interval + $this->delta;
}

public function getDelta()
{
return $this->delta;
}
}
179 changes: 179 additions & 0 deletions src/Retry/BackOff/LinearBackOffPolicy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
<?php

namespace Retry\BackOff;

use Retry\RetryContextInterface;

/**
* Implementation of {@link BackOffPolicyInterface} that linearly increases the back-off period for each retry attempt in a given set.
*/
class LinearBackOffPolicy extends AbstractBackOffPolicy
{
/**
* The default initial interval value - 100 ms.
*
* @var int
*/
const DEFAULT_INITIAL_INTERVAL = 1000;

/**
* The default maximum back-off time (30 seconds).
*
* @var int
*/
const DEFAULT_MAX_INTERVAL = 30000;

/**
* The default delta value (1 second).
*
* @var float
*/
const DEFAULT_DELTA_INTERVAL = 1000;

/**
* The initial sleep interval.
*
* @var int
*/
private $initialInterval;

/**
* The maximum value of the back-off period in milliseconds.
*
* @var int
*/
private $maxInterval;

/**
* The value to linearly increment the seed with for each retry attempt.
*
* @var float
*/
private $deltaInterval;

/**
* @var SleeperInterface
*/
private $sleeper;

/**
* @param int $initialInterval The initial sleep interval value. Default is 100 ms.
* Cannot be set to a value less than one.
* @param float $deltaInterval The delta value. Default is 1000.
* @param int $maxInterval The maximum back off period. Default is 30000 (30 seconds).
* The value will be reset to 1 if this method is called with a value less than 1.
* Set this to avoid infinite waits if backing-off a large number of times.
*/
public function __construct($initialInterval = null, $deltaInterval = null, $maxInterval = null)
{
if ($initialInterval === null) {
$initialInterval = self::DEFAULT_INITIAL_INTERVAL;
}

if ($deltaInterval === null) {
$deltaInterval = self::DEFAULT_DELTA_INTERVAL;
}

if ($maxInterval === null) {
$maxInterval = self::DEFAULT_MAX_INTERVAL;
}

$this->setInitialInterval($initialInterval);
$this->setDeltaInterval($deltaInterval);
$this->setMaxInterval($maxInterval);

$this->sleeper = new DefaultSleeper();
}

/**
* The initial period to sleep on the first back-off.
*
* @return int The initial interval
*/
public function getInitialInterval()
{
return $this->initialInterval;
}

/**
* Set the initial sleep interval value. Default is 1000 millisecond.
* Cannot be set to a value less than one.
*
* @param int $initialInterval
* @return void
*/
public function setInitialInterval($initialInterval)
{
$this->initialInterval = max(1, (int) $initialInterval);
}

/**
* The delta to use to generate the next back-off interval from the last.
*
* @return int The delta in use
*/
public function getDeltaInterval()
{
return $this->deltaInterval;
}

/**
* Set the delta interval value. Default is 1000.
*
* @param float $delta
* @return void
*/
public function setDeltaInterval($delta)
{
$this->deltaInterval = max(1, (int) $delta);
}

/**
* The maximum interval to sleep for. Defaults to 30 seconds.
*
* @return int The maximum interval.
*/
public function getMaxInterval()
{
return $this->maxInterval;
}

/**
* Setter for maximum back-off period. Default is 30000 (30 seconds).
* The value will be reset to 1 if this method is called with a value less than 1.
* Set this to avoid infinite waits if backing off a large number of times.
*
* @param int $maxInterval
* @return void
*/
public function setMaxInterval($maxInterval)
{
$this->maxInterval = max(1, (int) $maxInterval);
}

/**
* @param \Retry\BackOff\SleeperInterface $sleeper
* @return void
*/
public function setSleeper(SleeperInterface $sleeper)
{
$this->sleeper = $sleeper;
}

public function start(RetryContextInterface $context = null)
{
return new LinearBackOffContext($this->initialInterval, $this->deltaInterval, $this->maxInterval);
}

/**
* @param BackOffContextInterface|LinearBackOffContext $context
*/
public function backOff(BackOffContextInterface $context = null)
{
if (!$context instanceof LinearBackOffContext) {
throw new \InvalidArgumentException('Context is expected to be an instanceof LinearBackOffContext.');
}

$this->sleeper->sleep($context->getIntervalAndIncrement());
}
}
69 changes: 69 additions & 0 deletions tests/Retry/Test/BackOff/LinearBackOffPolicyTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

namespace Retry\Test\Retry\BackOff;

use Retry\BackOff\LinearBackOffPolicy;
use Retry\Test\BackOff\Fixtures\DummySleeper;

class LinearBackOffPolicyTest extends \PHPUnit_Framework_TestCase
{
/**
* @var LinearBackOffPolicy
*/
private $policy;

/**
* @var DummySleeper
*/
private $sleeper;

protected function setUp()
{
$this->policy = new LinearBackOffPolicy();
$this->sleeper = new DummySleeper();
$this->policy->setSleeper($this->sleeper);
}

protected function tearDown()
{
$this->policy = null;
$this->sleeper = null;
}

public function testSingleBackOff()
{
$context = $this->policy->start();
$this->policy->backOff($context);

$this->assertEquals(LinearBackOffPolicy::DEFAULT_INITIAL_INTERVAL, $this->sleeper->getLastBackOff());
}

public function testMaximumBackOff()
{
$this->policy->setMaxInterval(50);

$context = $this->policy->start();
$this->policy->backOff($context);

$this->assertEquals(50, $this->sleeper->getLastBackOff());
}

public function testMultiBackOff()
{
$seed = 100;
$delta = 10;

$this->policy->setInitialInterval($seed);
$this->policy->setDeltaInterval($delta);

$context = $this->policy->start();

for ($x = 0; $x < 5; $x++) {
$this->policy->backOff($context);
$this->assertEquals($seed, $this->sleeper->getLastBackOff());

$seed += $delta;
}
}
}

0 comments on commit 8d72645

Please sign in to comment.