Skip to content

[Messenger] MultiplierRetryStrategy int type overflow #57779

Closed
@rela589n

Description

@rela589n

Symfony version(s) affected

7.1

Description

Currently we face following error:

{
    "class": "ValueError",
    "message": "random_int(): Argument #1 ($min) must be less than or equal to argument #2 ($max)",
    "file": "vendor/symfony/messenger/Retry/MultiplierRetryStrategy.php:87",
    "trace": [
        "vendor/symfony/messenger/Retry/MultiplierRetryStrategy.php:87",
        "vendor/symfony/messenger/EventListener/SendFailedMessageForRetryListener.php:66",
        "vendor/symfony/event-dispatcher/EventDispatcher.php:246",
        "vendor/symfony/event-dispatcher/EventDispatcher.php:206",
        "vendor/symfony/event-dispatcher/EventDispatcher.php:56",
        "vendor/symfony/messenger/Worker.php:198",
        "vendor/symfony/messenger/Worker.php:174",
        "vendor/symfony/messenger/Worker.php:109",
        "vendor/symfony/messenger/Command/ConsumeMessagesCommand.php:244",
        "vendor/symfony/console/Command/Command.php:279",
        "vendor/symfony/console/Application.php:1047",
        "vendor/symfony/framework-bundle/Console/Application.php:123",
        "vendor/symfony/console/Application.php:316",
        "vendor/symfony/framework-bundle/Console/Application.php:77",
        "vendor/symfony/console/Application.php:167",
        "vendor/symfony/runtime/Runner/Symfony/ConsoleApplicationRunner.php:49",
        "vendor/autoload_runtime.php:29",
        "bin/console:15"
    ]
}

It seems that $randomness is overflowed in such way that it becomes a negative integer.

Hence, random_int stumbles over it:

$randomness = (int) ($delay * $this->jitter);
$delay += random_int(-$randomness, +$randomness);

How to reproduce

  1. Configure async transport with quite high max retries count:
framework:
    messenger:
        transports:
            async_two_phase_commit:
                dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
                options:
                    auto_setup: true
                    exchange:
                        name: two_phase_commit
                    queues:
                        messages_two_phase_commit: ~
                retry_strategy:
                    max_retries: 512
                    delay: 1000
                    multiplier: 2
                    max_delay: 7_200_000 # 2 hours
  1. Configure message routing to this transport:
framework:
    messenger:
        routing:
            App\YourMessage: async_two_phase_commit
  1. Dispatch your deliberately failing message into the bus:
    public function __construct(
        private MessageBusInterface $bus,
    ) {
    }

    public function __invoke(): void
    {
        $this->bus->dispatch(new YourMessage());
    }
  1. Wait until delay overflows
  2. See that after quite a time the error bloats up in a tremendous number of failures in the logs

Possible Solution

In case when $this->maxDelayMilliseconds is configured (2 hours in the above example), it would make sense not to calculate the hypothetical delay that could've been in case if that option was absent.

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions