Skip to content

[Messenger] Add option to set custom delay on RecoverableMessageHandlingException #57756

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
jannes-io opened this issue Jul 17, 2024 · 1 comment · Fixed by #57915
Closed

Comments

@jannes-io
Copy link

Description

Add an optional argument to the RecoverableMessageHandlingException that allows messenger to delay the retry for longer than the configured retry if the developer already knows that it'll take longer, but should be retried.

Useful in many scenarios, the code example uses the Retry-After header that is often accompanied by a 503. Some APIs with rate limits will also include headers when a rate limit is hit for when it can be retried.
Or simply to delay the retry of this 1 message, while all other messages should adhere to the configured retry timeouts.

Example

Before:

#[AsMessageHandler]
class ExampleMessageHandler
{
    public function __invoke(ExampleMessage $message): void
    {
        try {
            (new Client())->get('http://someapi');
        } catch (ServerException $ex) {
            $retryAfter = $this->parseResponseRetryAfter($ex->getResponse());
            $this->messageBus->dispatch(new ExampleMessage(), [new DelayStamp($retryAfter)]);
        } 
    }
}

Message is interpreted as a new message, previous retries, stamps,... are discarded.

After:

#[AsMessageHandler]
class ExampleMessageHandler
{
    public function __invoke(ExampleMessage $message): void
    {
        try {
            (new Client())->get('http://someapi');
        } catch (ServerException $ex) {
            $retryAfter = $this->parseResponseRetryAfter($ex->getResponse());
            throw new RecoverableMessageHandlingException(retryAfter: $retryAfter);
        }
    }
}

Message retains all of its previous stamps etc, but a delay stamp is added when the message can be retried again that may be larger (or smaller) than the default retry time.

@PawelPodkalicki
Copy link

I was trying to achieve the same goal. I think that I found a workaround. Instead of throwing an exception I dispatch a new messasge with stamps: DelayStamp and RedeliveryStamp. I get retry count for RedeliveryStamp from additional arguments (https://symfony.com/doc/current/messenger.html#additional-handler-arguments).

public function resolveAdditionalArgument(Envelope $envelope): array
{
    return ['retryCount' => RedeliveryStamp::getRetryCountFromEnvelope($envelope)];
}

Also maximal number of retries must be checked during exception handling. If exceeded, UnrecoverableMessageHandlingException should be thrown.

Redispatch (https://symfony.com/doc/current/messenger.html#redispatching-a-message) did not work because RedispatchMessageHandler does not pass stamps.

If anyone has better approach, please comment.

nicolas-grekas added a commit that referenced this issue Aug 13, 2024
…ceptionInterface (valtzu)

This PR was merged into the 7.2 branch.

Discussion
----------

[Messenger] Allow setting retry delay by RecoverableExceptionInterface

| Q             | A
| ------------- | ---
| Branch?       | 7.2
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Issues        | Fix #57756
| License       | MIT

Allow overriding retry delay from the retry strategy by providing it in the exception. Example use case is retrying http request based on `Retry-After` header.

Commits
-------

68a096c Allow setting retry delay by RecoverableExceptionInterface
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants