Symfony Messenger
Async message bus. Dispatch a message; a worker process picks it up later and runs the handler.
- Dispatch with `$bus->dispatch(new GenerateReport($id))`. The matching handler runs either sync or async depending on routing.
- Transports move messages: `doctrine`, `redis`, `amqp`, `sns`/`sqs`, plus the in-memory `sync` and `failed` transports.
- `framework.messenger.routing` maps message classes to transports.
- Run workers with `bin/console messenger:consume <transport> --time-limit=3600`.
- Failed messages go to the failure transport — inspect with `messenger:failed:show`, retry with `messenger:failed:retry`.
- Stamps attach metadata (delay, retry count, bus name) to messages without polluting the message class.
// Dispatch from anywhere
$this->bus->dispatch(new SendInvoice($invoiceId));
#[AsMessageHandler]
final class SendInvoiceHandler
{
public function __invoke(SendInvoice $msg): void { /* ... */ }
}
Common gotchas
- Workers must be restarted after deploy — they hold the OLD container in memory. Use `messenger:stop-workers` and a process supervisor (Supervisor, systemd) to restart.
- Long-running handlers can hit memory limits. Use `--memory-limit` and `--time-limit` and let the supervisor restart the worker.