akor
akor

Reputation: 193

Custom exception from Messenger handler

I try Symfony 4.3.0-dev version to get some new features from Messenger component. My command bus works in sync mode.

Before upgrading I could easily throw my custom exception ConflictException from handler. But for 4.3.0-dev I get a Symfony\Component\Messenger\Exception\HandlerFailedException.

How can I catch my custom exception again?

Upvotes: 4

Views: 7065

Answers (2)

yivi
yivi

Reputation: 47639

Starting with Symfony 4.3, if a handler throws any exception, it will be wrapped in a Symfony\Component\Messenger\Exception\HandlerFailedException.

This is reflected here in the changelog:

[BC BREAK] A HandlerFailedException exception will be thrown if one or more handler fails.

In places where you are dealing with a synchronous transport and you want to deal with the original exception, you can do something similar to what Api-Platform does in this DispatchTrait:

namespace App\Infrastructure\Messenger;

use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Exception\HandlerFailedException;
use Symfony\Component\Messenger\MessageBusInterface;
use Throwable;

trait DispatchTrait
{

    private ?MessageBusInterface $messageBus;

    /**
     * @param object|Envelope $message
     * @return Envelope
     * @throws Throwable
     */
    private function dispatch($message): ?Envelope
    {
        try {
            return $this->messageBus->dispatch($message);
        } catch (HandlerFailedException $e) {
            while ($e instanceof HandlerFailedException) {
                /** @var Throwable $e */
                $e = $e->getPrevious();
            }

            throw $e;
        }
    }
}

(This version has no backwards compatibility, and does away with the MessageBus check, since I'm only using for internal applications I'm in control of).

In whatever class you are dispatching your message, you could do:

class FooController
{
    use DispatchTrait;

    public function __construct(MessageBusInterface $messageBus) {
        $this->messageBus = $messageBus;
    }

    public function __invoke(Request $request)
    {
        // however you create your message
        $command = Command::fromHttpRequest(); 

        try {
                $this->dispatch($command);
        }
        catch (ConflictException $e) {
            // deal with the original exception
        }
    }
}

Upvotes: 4

Massimiliano Arione
Massimiliano Arione

Reputation: 2476

As you can see on CHANGELOG, a BC break was introduced in version 4.3. In my application I was catching exceptions, and I solved by adding following code:

if ($exception instanceof HandlerFailedException) {
    $exception = $exception->getPrevious();
}

Upvotes: 2

Related Questions