Skip to content

Messenger (quick look) ​

Emails, image resizing, webhooks - work you don't want inside the HTTP request. Symfony Messenger is the queue abstraction (sync by default, transports when you grow up).

Mental model ​

  1. Create a message class (DTO of intent)
  2. Create a handler (__invoke(Message $message))
  3. $bus->dispatch($message) from a controller/command
  4. Transport: sync (dev), Doctrine, Redis, AMQP…
php
<?php

// Message
final class SendWelcomeEmail
{
    public function __construct(public readonly string $userEmail) {}
}

// Handler
final class SendWelcomeEmailHandler
{
    public function __construct(private MailerInterface $mailer) {}

    public function __invoke(SendWelcomeEmail $message): void
    {
        // send mail…
    }
}
php
<?php

$bus->dispatch(new SendWelcomeEmail($user->getEmail()));

Comments for the code above:

  • Handler is auto-registered when it type-hints the message
  • Locally, MESSENGER_TRANSPORT_DSN=sync:// runs handlers inline - easy debugging
  • Prod: real transport + messenger:consume worker process

Consume workers ​

bash
php bin/console messenger:consume async -vv

Deploy means "run HTTP and consumers" - same ops lesson as Laravel queues / Horizon.

When to bother ​

Keep in requestDispatch to Messenger
Validate + save postResize upload
Return JSONCall slow third-party API
Tiny email in free-time toy appsBulk mail / digests

As you can see, it's the same "don't block the response" instinct you have with background jobs on the FE… except the failure modes are on your servers 😅

Next: where to go after this tutorial.

Best,

-- ł.

Continues after /lab/php-tutorial-for-fe-devs/