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
}
}
}