Upgrade Symfony to 4.3: Messenger Component changes

Vlad Gregurco
2 min readJun 15, 2019

--

Long road of upgrade…

Symfony 4.3 was released on 30 May and community started to upgrade their projects (I hope). It’s not a major release, but it includes a lot of changes and it’s one step closer to LTS version (4.4).

Upgrade

Generally it’s quite easy to upgrade a minor version. There is a special guide posted by Symfony: link. First you change versions in composer.json and run composer command. Voilà, you’re upgraded, but after that the game begins.

Problem

I met a strange behavior in Messenger component. Some of my handlers in specific cases throw exceptions. For example, NotFoundHttpException in case some data is not found in DB. Usually these exceptions are catched by ExceptionListener and responses with 500 status code are transformed in user-friendly ones. In case of NotFoundHttpException it is 404 status code, but not after update! After update all handlers started to throw 500 error.

I found a small mention in CHANGELOG:

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

This change was created in PR #30020 [Messenger] Ensure message is handled only once per handler. The idea of PR is clear from the title. Seeing the code we can observe that they enveloped execution of handlers in try/catch block (line 68) and if at least one handler threw exception, new HandlerFailedException is thrown (line 82). All the time all exceptions are replaced by this new one.

Solution

The solution is quite simple. We have to create new middleware, that will be executed after HandleMessageMiddleware and reproduce the old behavior:

<?php

namespace App\Middleware;

use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Exception\HandlerFailedException;
use Symfony\Component\Messenger\Middleware\MiddlewareInterface;
use Symfony\Component\Messenger\Middleware\StackInterface;

class FailureCatcherMiddleware implements MiddlewareInterface
{
/**
*
@param Envelope $envelope
*
@param StackInterface $stack
*
*
@return Envelope
*/
public function handle(Envelope $envelope, StackInterface $stack): Envelope
{
try {
$returnedEnvelope = $stack->next()->handle($envelope, $stack);
} catch (HandlerFailedException $e) {
throw $e->getNestedExceptions()[0];
}

return $returnedEnvelope;
}
}

and configure it in config/packages/messenger.yaml:

framework:
messenger:
buses:
messenger.bus.default:
middleware:
- 'App\Middleware\FailureCatcherMiddleware'

After these changes NotFoundHttpException will continue to cause 404 response!

Note

This solution perfectly works for synchronous messages handled during request/response flow. You have to adjust the middleware in case of async operations handled from console.

--

--