Skip to content

Commit

Permalink
Added support for exception handlers that return promises.
Browse files Browse the repository at this point in the history
Upgraded amp minimum version from 2.0 -> 2.1 to fix timer issue #243.
  • Loading branch information
Bilge committed Feb 10, 2019
1 parent a67d336 commit 68633ae
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 7 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
},
"require-dev": {
"phpunit/phpunit": "^4.8",
"amphp/amp": "^2"
"amphp/amp": "^2.1"
},
"autoload": {
"files": [
Expand Down
13 changes: 10 additions & 3 deletions src/retry.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
function retry($tries, callable $operation, callable $onError = null)
{
/** @var \Generator $generator */
$generator = (static function () use ($tries, $operation, $onError) {
$generator = (static function () use ($tries, $operation, $onError): \Generator {
// Nothing to do if tries less than or equal to zero.
if (($tries |= 0) <= $attempts = 0) {
return;
}
Expand All @@ -39,8 +40,14 @@ function retry($tries, callable $operation, callable $onError = null)
throw new FailingTooHardException($attempts, $exception);
}

if ($onError && $onError($exception) === false) {
return;
if ($onError) {
if (($result = $onError($exception)) instanceof Promise) {
$result = yield $result;
}

if ($result === false) {
return;
}
}

goto beginning;
Expand Down
64 changes: 61 additions & 3 deletions test/RetryAsyncTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
namespace ScriptFUSIONTest\Retry;

use Amp\Delayed;
use Amp\Promise;
use Amp\Success;
use ScriptFUSION\Retry\FailingTooHardException;

final class RetryAsyncTest extends \PHPUnit_Framework_TestCase
Expand Down Expand Up @@ -94,7 +96,7 @@ public function testFailingTooHardAsync()
}

/**
* These that the error callback is called before each retry.
* Tests that the error callback is called before each retry.
*/
public function testErrorCallbackAsync()
{
Expand All @@ -120,13 +122,37 @@ public function testErrorCallbackAsync()
}

/**
* Tests that an error handler that returns false aborts retrying.
* Tests that an error callback that returns a promise has its promise resolved.
*/
public function testPromiseErrorCallback()
{
$delay = 250; // Quarter of a second.
$start = microtime(true);

try {
\Amp\Promise\wait(
\ScriptFUSION\Retry\retryAsync($tries = 3, static function () {
throw new \DomainException;
}, static function () use ($delay): Promise {
return new Delayed($delay);
})
);
} catch (FailingTooHardException $outerException) {
self::assertInstanceOf(\DomainException::class, $outerException->getPrevious());
}

self::assertTrue(isset($outerException));
self::assertGreaterThan($start + $delay * ($tries - 1) / 1000, microtime(true));
}

/**
* Tests that when error handler that returns false, it aborts retrying.
*/
public function testErrorCallbackHaltAsync()
{
$invocations = 0;

\ScriptFUSION\Retry\retryAsync($tries = 2, static function () use (&$invocations) {
\ScriptFUSION\Retry\retryAsync(2, static function () use (&$invocations) {
++$invocations;

throw new \RuntimeException;
Expand All @@ -136,4 +162,36 @@ public function testErrorCallbackHaltAsync()

self::assertSame(1, $invocations);
}

/**
* Tests that when an error handler returns a promise that false, it aborts retrying.
*/
public function testPromiseErrorCallbackHaltAsync()
{
$invocations = 0;

\ScriptFUSION\Retry\retryAsync(2, static function () use (&$invocations) {
++$invocations;

throw new \RuntimeException;
}, static function (): Promise {
return new Success(false);
});

self::assertSame(1, $invocations);
}

/**
* Tests that the exception handler can throw an exception that will not be caught.
*/
public function testErrorCallbackCanThrow()
{
$this->setExpectedException(\LogicException::class);

\ScriptFUSION\Retry\retryAsync(2, static function () {
throw new \RuntimeException;
}, static function () {
throw new \LogicException;
});
}
}

0 comments on commit 68633ae

Please sign in to comment.