Skip to content

Commit

Permalink
Optimized retry helper function can accept array as first parameter…
Browse files Browse the repository at this point in the history
…. (#6539)


Co-authored-by: 李铭昕 <[email protected]>
  • Loading branch information
huangdijia and limingxinleo authored Feb 18, 2024
1 parent 5f3bb35 commit f59b668
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 2 deletions.
57 changes: 57 additions & 0 deletions src/Backoff/ArrayBackoff.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact [email protected]
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Support\Backoff;

use Hyperf\Collection\Arr;
use InvalidArgumentException;

class ArrayBackoff
{
private int $lastMillisecond;

/**
* @param array $milliseconds backoff interval
*/
public function __construct(private array $milliseconds)
{
if (empty($milliseconds)) {
throw new InvalidArgumentException(
'The backoff interval milliseconds cannot be empty.'
);
}

$this->lastMillisecond = (int) array_pop($this->milliseconds);
}

/**
* Sleep until the next execution.
*/
public function sleep(): void
{
$ms = (int) (array_shift($this->milliseconds) ?? $this->lastMillisecond);

if ($ms === 0) {
return;
}

usleep($ms * 1000);
}

/**
* Get the next backoff for logging, etc.
* @return int next backoff
*/
public function nextBackoff(): int
{
return (int) Arr::first($this->milliseconds, default: $this->lastMillisecond);
}
}
10 changes: 8 additions & 2 deletions src/Functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Hyperf\Collection\Arr;
use Hyperf\Context\ApplicationContext;
use Hyperf\Stringable\StrCache;
use Hyperf\Support\Backoff\ArrayBackoff;
use Throwable;

/**
Expand Down Expand Up @@ -60,14 +61,19 @@ function env($key, $default = null)
/**
* Retry an operation a given number of times.
*
* @param float|int $times
* @param float|int|int[] $times
* @param int $sleep millisecond
* @throws Throwable
*/
function retry($times, callable $callback, int $sleep = 0)
{
$attempts = 0;
$backoff = new Backoff($sleep);
if (is_array($times)) {
$backoff = new ArrayBackoff($times);
$times = count($times);
} else {
$backoff = new Backoff($sleep);
}

beginning:
try {
Expand Down
11 changes: 11 additions & 0 deletions tests/BackoffTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,15 @@ public function testBackoff()
$this->assertGreaterThanOrEqual(1, $secondTick);
$this->assertLessThanOrEqual(3 * $firstTick, $secondTick);
}

public function testCustomBackoff()
{
$backoff = new Backoff\ArrayBackoff([1, 200]);
$backoff->sleep();
$this->assertSame(200, $backoff->nextBackoff());

$backoff = new Backoff\ArrayBackoff([1, 2.2]);
$backoff->sleep();
$this->assertSame(2, $backoff->nextBackoff());
}
}
18 changes: 18 additions & 0 deletions tests/FunctionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,24 @@ public function testRetry()
}
}

public function testRetryTimesAsArray()
{
$this->expectException(RetryException::class);
$result = 0;
$milliSeconds[] = microtime(true);
try {
retry([100, 200], function () use (&$result, &$milliSeconds) {
++$result;
$milliSeconds[] = microtime(true);
throw new RetryException('Retry Test');
});
} finally {
$this->assertSame(3, $result);
$this->assertGreaterThanOrEqual(0.1, $milliSeconds[2] - $milliSeconds[1]);
$this->assertGreaterThanOrEqual(0.2, $milliSeconds[3] - $milliSeconds[2]);
}
}

public function testOneTimesRetry()
{
$this->expectException(RetryException::class);
Expand Down

0 comments on commit f59b668

Please sign in to comment.