説明なし

RetryMiddleware.php 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. <?php
  2. namespace GuzzleHttp;
  3. use GuzzleHttp\Promise\PromiseInterface;
  4. use GuzzleHttp\Promise\RejectedPromise;
  5. use GuzzleHttp\Psr7;
  6. use Psr\Http\Message\RequestInterface;
  7. /**
  8. * Middleware that retries requests based on the boolean result of
  9. * invoking the provided "decider" function.
  10. */
  11. class RetryMiddleware
  12. {
  13. /** @var callable */
  14. private $nextHandler;
  15. /** @var callable */
  16. private $decider;
  17. /**
  18. * @param callable $decider Function that accepts the number of retries,
  19. * a request, [response], and [exception] and
  20. * returns true if the request is to be
  21. * retried.
  22. * @param callable $nextHandler Next handler to invoke.
  23. * @param callable $delay Function that accepts the number of retries
  24. * and returns the number of milliseconds to
  25. * delay.
  26. */
  27. public function __construct(
  28. callable $decider,
  29. callable $nextHandler,
  30. callable $delay = null
  31. ) {
  32. $this->decider = $decider;
  33. $this->nextHandler = $nextHandler;
  34. $this->delay = $delay ?: __CLASS__ . '::exponentialDelay';
  35. }
  36. /**
  37. * Default exponential backoff delay function.
  38. *
  39. * @param $retries
  40. *
  41. * @return int
  42. */
  43. public static function exponentialDelay($retries)
  44. {
  45. return (int) pow(2, $retries - 1);
  46. }
  47. /**
  48. * @param RequestInterface $request
  49. * @param array $options
  50. *
  51. * @return PromiseInterface
  52. */
  53. public function __invoke(RequestInterface $request, array $options)
  54. {
  55. if (!isset($options['retries'])) {
  56. $options['retries'] = 0;
  57. }
  58. $fn = $this->nextHandler;
  59. return $fn($request, $options)
  60. ->then(
  61. $this->onFulfilled($request, $options),
  62. $this->onRejected($request, $options)
  63. );
  64. }
  65. private function onFulfilled(RequestInterface $req, array $options)
  66. {
  67. return function ($value) use ($req, $options) {
  68. if (!call_user_func(
  69. $this->decider,
  70. $options['retries'],
  71. $req,
  72. $value,
  73. null
  74. )) {
  75. return $value;
  76. }
  77. return $this->doRetry($req, $options);
  78. };
  79. }
  80. private function onRejected(RequestInterface $req, array $options)
  81. {
  82. return function ($reason) use ($req, $options) {
  83. if (!call_user_func(
  84. $this->decider,
  85. $options['retries'],
  86. $req,
  87. null,
  88. $reason
  89. )) {
  90. return new RejectedPromise($reason);
  91. }
  92. return $this->doRetry($req, $options);
  93. };
  94. }
  95. private function doRetry(RequestInterface $request, array $options)
  96. {
  97. $options['delay'] = call_user_func($this->delay, ++$options['retries']);
  98. return $this($request, $options);
  99. }
  100. }