Skip to content

Commit e2e1f78

Browse files
committed
Added AsyncExponentialBackoffExceptionHandler and accompanying test.
1 parent d0b8d7a commit e2e1f78

10 files changed

+95
-11
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace ScriptFUSION\Retry\ExceptionHandler;
5+
6+
use ScriptFUSION\Retry\ExceptionHandler\Sequence\PowersOfTwoSequence;
7+
8+
/**
9+
* Delays the current asynchronous execution context for an exponentially increasing series of delays.
10+
*
11+
* e.g. 102ms, 204ms, 408ms, 816ms, 1.632s...
12+
*/
13+
class AsyncExponentialBackoffExceptionHandler extends AsyncMilliSleepExceptionHandler
14+
{
15+
const DEFAULT_COEFFICIENT = 102;
16+
17+
private $millisecondCoefficient;
18+
19+
public function __construct(int $millisecondCoefficient = self::DEFAULT_COEFFICIENT)
20+
{
21+
parent::__construct($this->generateSequence($this->millisecondCoefficient = $millisecondCoefficient));
22+
}
23+
24+
private function generateSequence($coefficient): \Generator
25+
{
26+
foreach (new PowersOfTwoSequence as $base) {
27+
yield $base * $coefficient;
28+
}
29+
}
30+
}

src/AsyncMilliSleepExceptionHandler.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
use Amp\Delayed;
77

88
/**
9-
* Delays for a series of millisecond delays on each invocation.
9+
* Delays the current asynchronous execution context for a series of millisecond delays on each invocation.
1010
*/
1111
class AsyncMilliSleepExceptionHandler
1212
{
@@ -19,6 +19,7 @@ public function __construct(\Iterator $delays)
1919

2020
public function __invoke()
2121
{
22+
// TODO: Iterator validation. i.e. What happens when the iterator is no longer valid?
2223
$delay = $this->delays->current();
2324

2425
$this->delays->next();

src/ExponentialBackoffExceptionHandler.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
<?php declare(strict_types=1);
1+
<?php
2+
declare(strict_types=1);
23

34
namespace ScriptFUSION\Retry\ExceptionHandler;
45

56
use ScriptFUSION\Retry\ExceptionHandler\Sequence\PowersOfTwoSequence;
67

78
/**
89
* Sleeps for an exponentially increasing series of delays.
10+
*
11+
* e.g. 102ms, 204ms, 408ms, 816ms, 1.632s...
912
*/
1013
class ExponentialBackoffExceptionHandler extends MicroSleepExceptionHandler
1114
{

src/MicroSleepExceptionHandler.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
<?php declare(strict_types=1);
1+
<?php
2+
declare(strict_types=1);
23

34
namespace ScriptFUSION\Retry\ExceptionHandler;
45

src/Sequence/PowersOfTwoSequence.php

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1-
<?php declare(strict_types=1);
1+
<?php
2+
declare(strict_types=1);
23

34
namespace ScriptFUSION\Retry\ExceptionHandler\Sequence;
45

6+
/**
7+
* Represents a sequence of values of the power two.
8+
*
9+
* e.g. 1, 2, 4, 8, 16...
10+
*/
511
final class PowersOfTwoSequence implements \IteratorAggregate
612
{
713
private $power = 0;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace ScriptFUSIONTest\Retry\ExceptionHandler\Unit;
5+
6+
use PHPUnit\Framework\TestCase;
7+
use ScriptFUSION\Retry\ExceptionHandler\AsyncExponentialBackoffExceptionHandler;
8+
9+
/**
10+
* @see AsyncExponentialBackoffExceptionHandler
11+
*/
12+
final class AsyncExponentialBackoffExceptionHandlerTest extends TestCase
13+
{
14+
public function test()
15+
{
16+
$handler = new AsyncExponentialBackoffExceptionHandler;
17+
18+
\Amp\Loop::run(static function () use ($handler): \Generator {
19+
$start = microtime(true);
20+
21+
for ($counter = 0; $counter < 4; ++$counter) {
22+
yield $handler();
23+
}
24+
25+
self::assertGreaterThan($start + 1.5, microtime(true));
26+
});
27+
}
28+
}

test/Unit/AsyncMilliSleepExceptionHandlerTest.php

+4-4
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@ public function testSeries()
2727
new \ArrayIterator($delays = array_fill(0, $limit = 10, 100))
2828
);
2929

30-
$start = microtime(true);
31-
3230
\Amp\Loop::run(static function () use ($handler, $limit): \Generator {
31+
$start = microtime(true);
32+
3333
for ($counter = 0; $counter < $limit; ++$counter) {
3434
yield $handler();
3535
}
36-
});
3736

38-
self::assertGreaterThan($start + 1, microtime(true));
37+
self::assertGreaterThan($start + 1, microtime(true));
38+
});
3939
}
4040
}

test/Unit/ExponentialBackoffExceptionHandlerTest.php

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
<?php declare(strict_types=1);
1+
<?php
2+
declare(strict_types=1);
23

34
namespace ScriptFUSIONTest\Retry\Unit\ExceptionHandler;
45

56
use PHPUnit\Framework\TestCase;
67
use ScriptFUSION\Retry\ExceptionHandler\ExponentialBackoffExceptionHandler;
78

9+
/**
10+
* @see ExponentialBackoffExceptionHandler
11+
*/
812
final class ExponentialBackoffExceptionHandlerTest extends TestCase
913
{
1014
public function test()

test/Unit/MicroSleepExceptionHandlerTest.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
<?php declare(strict_types=1);
1+
<?php
2+
declare(strict_types=1);
23

34
namespace ScriptFUSIONTest\Retry\Unit\ExceptionHandler;
45

test/Unit/Sequence/PowersOfTwoSequenceTest.php

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,29 @@
1-
<?php declare(strict_types=1);
1+
<?php
2+
declare(strict_types=1);
23

34
namespace ScriptFUSIONTest\Retry\Unit\ExceptionHandler\Sequence;
45

56
use PHPUnit\Framework\TestCase;
67
use ScriptFUSION\Retry\ExceptionHandler\Sequence\PowersOfTwoSequence;
78

9+
/**
10+
* @see PowersOfTwoSequence
11+
*/
812
final class PowersOfTwoSequenceTest extends TestCase
913
{
14+
/**
15+
* Tests that the iterator yields the expected sequence values.
16+
*/
1017
public function testSequence()
1118
{
1219
$powers = new \LimitIterator((new PowersOfTwoSequence)->getIterator(), 0, 6);
1320

1421
self::assertSame([1, 2, 4, 8, 16, 32], iterator_to_array($powers));
1522
}
1623

24+
/**
25+
* Tests that the iterator will not yield values forever.
26+
*/
1727
public function testIsFiniteSequence()
1828
{
1929
$counter = 0;

0 commit comments

Comments
 (0)