Skip to content

Commit

Permalink
New retry helpers
Browse files Browse the repository at this point in the history
- `retry_timeout` - Repeats the callback until the answer is returned or timeout occurs
- `retry_count` - Repeats the callback until the answer is returned or the callback starts N times
  • Loading branch information
acelot committed Dec 24, 2018
1 parent a203b66 commit 2d4d596
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 0 deletions.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"src/array_helpers.php",
"src/common_helpers.php",
"src/date_helpers.php",
"src/retry_helpers.php",
"src/string_helpers.php"
]
},
Expand Down
56 changes: 56 additions & 0 deletions src/retry_helpers.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php declare(strict_types=1);

namespace Acelot\Helpers;

const SECONDS = 1000000;
const MILLISECONDS = 1000;

/**
* Repeats the callback until the answer is returned or timeout occurs.
*
* @param callable $callable Callback function
* @param int $timeout Microseconds
* @param int $pause Pause between repeats in microseconds
*
* @return mixed
* @throws \Throwable
*/
function retry_timeout(callable $callable, int $timeout, int $pause = 0)
{
$start = microtime(true);

while (true) {
try {
return $callable();
} catch (\Throwable $e) {
if (microtime(true) - $start > ($timeout / SECONDS)) {
throw $e;
}
usleep($pause);
}
}
}

/**
* Repeats the callback until the answer is returned or the callback starts N times.
*
* @param callable $callable Callback function
* @param int $count Max number of tries
* @param int $pause Pause between repeats in microseconds
*
* @return mixed
* @throws \Throwable
*/
function retry_count(callable $callable, int $count, int $pause = 0)
{
while (true) {
try {
return $callable();
} catch (\Throwable $e) {
if (--$count === 0) {
throw $e;
}
usleep($pause);
}
}
}
68 changes: 68 additions & 0 deletions tests/RetryHelpersTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

namespace Acelot\Helpers\Tests;

use const Acelot\Helpers\MILLISECONDS;
use function Acelot\Helpers\retry_count;
use function Acelot\Helpers\retry_timeout;
use PHPUnit\Framework\TestCase;

class RetryHelpersTest extends TestCase
{
public function testShouldFailOnTimeout()
{
$this->expectException(\Exception::class);

retry_timeout(function () {
throw new \Exception('test');
}, 1 * MILLISECONDS, 10);
}

public function testSuccessAfterOneHundredMilliSecond()
{
$i = 0;

try {
$start = microtime(true);

retry_timeout(
function () use (&$i) {
if (++$i > 10) return true;
throw new \Exception('test');
},
200 * MILLISECONDS,
10 * MILLISECONDS
);

$end = microtime(true) - $start;
$this->assertTrue($end > 0.1 && $end < 0.2);
} catch (\Exception $e) {
$this->fail();
}
}

public function testShouldFailOnMaxCount()
{
$this->expectException(\Exception::class);

retry_count(function () {
throw new \Exception('test');
}, 5, 10 * MILLISECONDS);
}

public function testSuccessAfterFiveTries()
{
$i = 0;

try {
$retries = retry_count(function () use (&$i) {
if (++$i === 5) return $i;
throw new \Exception('test');
}, 1 * MILLISECONDS, 10);

$this->assertEquals(5, $retries);
} catch (\Exception $e) {
$this->fail();
}
}
}

0 comments on commit 2d4d596

Please sign in to comment.