MultiplierRetryStrategy.php 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Messenger\Retry;
  11. use Symfony\Component\Messenger\Envelope;
  12. use Symfony\Component\Messenger\Exception\InvalidArgumentException;
  13. use Symfony\Component\Messenger\Stamp\RedeliveryStamp;
  14. /**
  15. * A retry strategy with a constant or exponential retry delay.
  16. *
  17. * For example, if $delayMilliseconds=10000 & $multiplier=1 (default),
  18. * each retry will wait exactly 10 seconds.
  19. *
  20. * But if $delayMilliseconds=10000 & $multiplier=2:
  21. * * Retry 1: 10 second delay
  22. * * Retry 2: 20 second delay (10000 * 2 = 20000)
  23. * * Retry 3: 40 second delay (20000 * 2 = 40000)
  24. *
  25. * @author Ryan Weaver <ryan@symfonycasts.com>
  26. *
  27. * @final
  28. */
  29. class MultiplierRetryStrategy implements RetryStrategyInterface
  30. {
  31. private $maxRetries;
  32. private $delayMilliseconds;
  33. private $multiplier;
  34. private $maxDelayMilliseconds;
  35. /**
  36. * @param int $maxRetries The maximum number of times to retry
  37. * @param int $delayMilliseconds Amount of time to delay (or the initial value when multiplier is used)
  38. * @param float $multiplier Multiplier to apply to the delay each time a retry occurs
  39. * @param int $maxDelayMilliseconds Maximum delay to allow (0 means no maximum)
  40. */
  41. public function __construct(int $maxRetries = 3, int $delayMilliseconds = 1000, float $multiplier = 1, int $maxDelayMilliseconds = 0)
  42. {
  43. $this->maxRetries = $maxRetries;
  44. if ($delayMilliseconds < 0) {
  45. throw new InvalidArgumentException(sprintf('Delay must be greater than or equal to zero: "%s" given.', $delayMilliseconds));
  46. }
  47. $this->delayMilliseconds = $delayMilliseconds;
  48. if ($multiplier < 1) {
  49. throw new InvalidArgumentException(sprintf('Multiplier must be greater than zero: "%s" given.', $multiplier));
  50. }
  51. $this->multiplier = $multiplier;
  52. if ($maxDelayMilliseconds < 0) {
  53. throw new InvalidArgumentException(sprintf('Max delay must be greater than or equal to zero: "%s" given.', $maxDelayMilliseconds));
  54. }
  55. $this->maxDelayMilliseconds = $maxDelayMilliseconds;
  56. }
  57. /**
  58. * @param \Throwable|null $throwable The cause of the failed handling
  59. */
  60. public function isRetryable(Envelope $message, \Throwable $throwable = null): bool
  61. {
  62. $retries = RedeliveryStamp::getRetryCountFromEnvelope($message);
  63. return $retries < $this->maxRetries;
  64. }
  65. /**
  66. * @param \Throwable|null $throwable The cause of the failed handling
  67. */
  68. public function getWaitingTime(Envelope $message, \Throwable $throwable = null): int
  69. {
  70. $retries = RedeliveryStamp::getRetryCountFromEnvelope($message);
  71. $delay = $this->delayMilliseconds * $this->multiplier ** $retries;
  72. if ($delay > $this->maxDelayMilliseconds && 0 !== $this->maxDelayMilliseconds) {
  73. return $this->maxDelayMilliseconds;
  74. }
  75. return $delay;
  76. }
  77. }