symfony/doctrine-messenger
Doctrine integration for Symfony Messenger: use Doctrine-backed transports and tooling to send, store, and process messages reliably within Symfony apps. Part of the Symfony ecosystem; issues and PRs are handled in the main symfony/symfony repository.
Install the Package
composer require symfony/doctrine-messenger
Ensure symfony/messenger and doctrine/dbal are also installed (required dependencies).
Configure Doctrine Transport
Add the transport to your config/packages/messenger.yaml:
framework:
messenger:
transports:
async: '%env(MESSENGER_TRANSPORT_DSN)%'
routing:
'App\Message\YourMessage': async
Define the DSN in .env:
MESSENGER_TRANSPORT_DSN=doctrine://default
Run Migrations Doctrine Messenger creates tables automatically, but run:
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
Dispatch a Message
use App\Message\YourMessage;
use Symfony\Component\Messenger\MessageBusInterface;
public function __construct(private MessageBusInterface $bus) {}
public function sendMessage(): void
{
$this->bus->dispatch(new YourMessage('Hello, Doctrine!'));
}
Consume Messages Start the worker:
php bin/console messenger:consume async -vv
Create a message class:
namespace App\Message;
class SendEmailMessage {
public function __construct(public string $email, public string $subject, public string $body) {}
}
Create a handler:
namespace App\MessageHandler;
use App\Message\SendEmailMessage;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
#[AsMessageHandler]
class SendEmailHandler {
public function __invoke(SendEmailMessage $message) {
// Logic to send email (e.g., using Symfony Mailer)
}
}
Dispatch from a controller:
$this->bus->dispatch(new SendEmailMessage(
'user@example.com',
'Welcome!',
'Thanks for signing up!'
));
config/packages/messenger.yaml (Transport and routing configuration).src/Message/ (Your message classes).src/MessageHandler/ (Handler logic).$this->bus->dispatch(new YourMessage());
async).
# config/packages/messenger.yaml
routing:
'App\Message\YourMessage': async
#[AsMessageHandler]
class YourHandler {
public function __invoke(YourMessage $message) {
// Handle logic
}
}
# config/packages/messenger.yaml
transports:
async:
dsn: doctrine://default
middleware:
- 'doctrine_transaction' # Built-in for transactions
- App\Middleware\YourMiddleware
php bin/console messenger:consume async --time-limit=300
* * * * * php /path/to/your/project/bin/console messenger:consume async --limit=100
messenger.yaml:
transports:
async:
dsn: doctrine://default
retry_strategy:
max_retries: 3
delay: 1000
multiplier: 2
message_history table or use:
php bin/console messenger:failed-messages-show
messenger.yaml:
transports:
async:
dsn: doctrine://default
middleware:
- doctrine_transaction
DoctrineTransactionMiddleware in custom middleware.// src/Doctrine/SchemaExtension.php
namespace App\Doctrine;
use Doctrine\DBAL\Schema\Schema;
use Symfony\Component\Messenger\Transport\Doctrine\DoctrineTransport;
class SchemaExtension {
public function __invoke(Schema $schema, DoctrineTransport $transport) {
$schema->getTable($transport->getTableName())->addColumn('custom_field', 'string');
}
}
Register in config/packages/messenger.yaml:
transports:
async:
dsn: doctrine://default
schema_extension: App\Doctrine\SchemaExtension
transports:
async:
dsn: doctrine://default
options:
batch_size: 50
routing:
'App\Message\HighPriorityMessage': high_priority
'App\Message\LowPriorityMessage': low_priority
transports:
high_priority:
dsn: doctrine://default
options:
priority: 1
low_priority:
dsn: doctrine://default
options:
priority: 2
# config/packages/test/messenger.yaml
transports:
test:
dsn: 'doctrine://default'
options:
table_name: 'test_messages'
MessageBusInterface mocks in PHPUnit:
$bus = $this->createMock(MessageBusInterface::class);
$bus->expects($this->once())->method('dispatch');
Schema Conflicts
message, message_history). Conflicts arise if these names clash with existing tables.MESSENGER_TRANSPORT_DSN=doctrine://default?table_name=app_messages&history_table_name=app_message_history
Transaction Deadlocks
doctrine_transaction middleware sparingly or optimize handler logic. Avoid nested transactions.PostgreSQL Listener Issues
UNLISTEN queries are sent unnecessarily (fixed in v8.0.5+).Firebird/Oracle Compatibility
transports:
async:
dsn: doctrine://default
options:
table_name: "MESSAGES" # Quoted for Firebird
Message Size Limits
serialize for complex data or store references to external storage (e.g., S3).Check Failed Messages
php bin/console messenger:failed-messages-show
php bin/console messenger:failed-messages-retry [ID]
Enable Verbose Logging
php bin/console messenger:consume async -vv
Or configure in config/packages/monolog.yaml:
handlers:
messenger:
type: stream
path: "%kernel.logs_dir%/messenger.log"
level: debug
Inspect Database Tables
-- Check pending messages
SELECT * FROM message WHERE status = 'envelope';
-- Check history (retries, failures)
SELECT * FROM message_history ORDER BY created_at DESC;
Slow Consumption
How can I help you explore Laravel packages today?