Skip to content

Commit c87566a

Browse files
authored
Allow a callable parameter to decide if require is going to be retrie… (#79)
* Allow a callable parameter to decide if require is going to be retried or not. Also allow retry backoff * Applied changes from StyleCI * Some fixes * Applied changes from StyleCI * Updated changelog * Stuff
1 parent fd4fd0a commit c87566a

File tree

3 files changed

+59
-1
lines changed

3 files changed

+59
-1
lines changed

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,18 @@
55
### Added
66

77
- `PluginClientFactory` to create `PluginClient` instances.
8+
- Added new option 'delay' for `RetryPlugin`.
9+
- Added new option 'decider' for `RetryPlugin`.
10+
11+
### Changed
12+
13+
- The `RetryPlugin` does now wait between retries. To disable/change this feature you must write something like:
14+
15+
```php
16+
$plugin = new RetryPlugin(['delay' => function(RequestInterface $request, Exception $e, $retries) {
17+
return 0;
18+
});
19+
```
820

921
### Deprecated
1022

spec/Plugin/RetryPluginSpec.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,12 @@ function it_does_not_keep_history_of_old_failure(RequestInterface $request, Resp
101101
$this->handleRequest($request, $next, function () {})->shouldReturnAnInstanceOf('Http\Client\Promise\HttpFulfilledPromise');
102102
$this->handleRequest($request, $next, function () {})->shouldReturnAnInstanceOf('Http\Client\Promise\HttpFulfilledPromise');
103103
}
104+
105+
function it_has_an_exponential_default_delay(RequestInterface $request, Exception\HttpException $exception)
106+
{
107+
$this->defaultDelay($request, $exception, 0)->shouldBe(1000);
108+
$this->defaultDelay($request, $exception, 1)->shouldBe(2000);
109+
$this->defaultDelay($request, $exception, 2)->shouldBe(4000);
110+
$this->defaultDelay($request, $exception, 3)->shouldBe(8000);
111+
}
104112
}

src/Plugin/RetryPlugin.php

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@ final class RetryPlugin implements Plugin
2424
*/
2525
private $retry;
2626

27+
/**
28+
* @var callable
29+
*/
30+
private $delay;
31+
32+
/**
33+
* @var callable
34+
*/
35+
private $decider;
36+
2737
/**
2838
* Store the retry counter for each request.
2939
*
@@ -35,18 +45,28 @@ final class RetryPlugin implements Plugin
3545
* @param array $config {
3646
*
3747
* @var int $retries Number of retries to attempt if an exception occurs before letting the exception bubble up.
48+
* @var callable $decider A callback that gets a request and an exception to decide after a failure whether the request should be retried.
49+
* @var callable $delay A callback that gets a request, an exception and the number of retries and returns how many milliseconds we should wait before trying again.
3850
* }
3951
*/
4052
public function __construct(array $config = [])
4153
{
4254
$resolver = new OptionsResolver();
4355
$resolver->setDefaults([
4456
'retries' => 1,
57+
'decider' => function (RequestInterface $request, Exception $e) {
58+
return true;
59+
},
60+
'delay' => __CLASS__.'::defaultDelay',
4561
]);
4662
$resolver->setAllowedTypes('retries', 'int');
63+
$resolver->setAllowedTypes('decider', 'callable');
64+
$resolver->setAllowedTypes('delay', 'callable');
4765
$options = $resolver->resolve($config);
4866

4967
$this->retry = $options['retries'];
68+
$this->decider = $options['decider'];
69+
$this->delay = $options['delay'];
5070
}
5171

5272
/**
@@ -73,12 +93,30 @@ public function handleRequest(RequestInterface $request, callable $next, callabl
7393
throw $exception;
7494
}
7595

76-
++$this->retryStorage[$chainIdentifier];
96+
if (!call_user_func($this->decider, $request, $exception)) {
97+
throw $exception;
98+
}
99+
100+
$time = call_user_func($this->delay, $request, $exception, $this->retryStorage[$chainIdentifier]);
101+
usleep($time);
77102

78103
// Retry in synchrone
104+
++$this->retryStorage[$chainIdentifier];
79105
$promise = $this->handleRequest($request, $next, $first);
80106

81107
return $promise->wait();
82108
});
83109
}
110+
111+
/**
112+
* @param RequestInterface $request
113+
* @param Exception $e
114+
* @param int $retries The number of retries we made before. First time this get called it will be 0.
115+
*
116+
* @return int
117+
*/
118+
public static function defaultDelay(RequestInterface $request, Exception $e, $retries)
119+
{
120+
return pow(2, $retries) * 1000;
121+
}
84122
}

0 commit comments

Comments
 (0)