Installation:
composer require php-amqplib/rabbitmq-bundle
Register the bundle in AppKernel.php:
new OldSound\RabbitMqBundle\OldSoundRabbitMqBundle(),
Configure RabbitMQ (config/packages/old_sound_rabbit_mq.yaml):
old_sound_rabbit_mq:
connections:
default:
host: 'localhost'
port: 5672
user: 'guest'
password: 'guest'
vhost: '/'
lazy: false
producers:
upload_picture_producer:
connection: default
exchange_options: {name: 'upload_pictures', type: direct}
consumers:
upload_picture_consumer:
connection: default
exchange_options: {name: 'upload_pictures', type: direct}
queue_options: {name: 'upload_pictures'}
callback: upload_picture_consumer
First Producer Use Case:
Create a service to publish messages (e.g., src/Service/UploadPictureProducer.php):
namespace App\Service;
use OldSound\RabbitMqBundle\RabbitMq\ProducerInterface;
class UploadPictureProducer
{
private $producer;
public function __construct(ProducerInterface $producer)
{
$this->producer = $producer;
}
public function publish(array $message)
{
$this->producer->publish(serialize($message));
}
}
Register it in services.yaml:
services:
App\Service\UploadPictureProducer:
arguments:
- '@old_sound_rabbit_mq.upload_picture_producer'
First Consumer Use Case:
Create a consumer class (e.g., src/MessageHandler/UploadPictureConsumer.php):
namespace App\MessageHandler;
use OldSound\RabbitMqBundle\RabbitMq\ConsumerInterface;
class UploadPictureConsumer implements ConsumerInterface
{
public function execute(array $message)
{
$data = unserialize($message['body']);
// Process $data['user_id'] and $data['image_path']
}
}
Producer Workflow:
use App\Service\UploadPictureProducer;
class UploadController extends AbstractController
{
public function uploadPicture(UploadPictureProducer $producer)
{
$producer->publish(['user_id' => 123, 'image_path' => '/path/to/image.jpg']);
return new Response('Message published!');
}
}
Consumer Workflow:
php bin/console rabbitmq:consumer -m 50 upload_picture_consumer
[program:upload_picture_consumer]
command=php /path/to/your/project/bin/console rabbitmq:consumer upload_picture_consumer
autostart=true
autorestart=true
user=www-data
numprocs=1
Message Serialization:
serialize()/unserialize() for simplicity (as shown in README).# config/packages/old_sound_rabbit_mq.yaml
old_sound_rabbit_mq:
producers:
upload_picture_producer:
serializer: serializer
use Symfony\Component\Serializer\SerializerInterface;
class UploadPictureProducer
{
public function __construct(
ProducerInterface $producer,
private SerializerInterface $serializer
) {}
public function publish(array $message)
{
$this->producer->publish(
$this->serializer->serialize($message, 'json')
);
}
}
Error Handling:
consumer section:
consumers:
upload_picture_consumer:
...
queue_options:
name: 'upload_pictures'
dead_letter_exchange: 'dead_letter_exchange'
ConsumerInterface with retry logic:
class RetryConsumer implements ConsumerInterface
{
private $maxRetries = 3;
public function execute(array $message)
{
try {
$this->realConsumer->execute($message);
} catch (\Exception $e) {
if ($this->maxRetries-- > 0) {
// Re-publish to DLX or retry queue
}
throw $e;
}
}
}
Dynamic Routing:
producers:
dynamic_producer:
exchange_options: {name: 'dynamic_exchange', type: direct}
$producer->publish(serialize($message), 'routing.key');
consumers:
dynamic_consumer:
queue_options: {name: 'dynamic_queue'}
exchange_options: {name: 'dynamic_exchange', type: direct}
binding_options: {routing_key: 'routing.key'}
Connection Management:
lazy: true in config to avoid connection overhead for infrequent producers.php-amqplib's Connection events).Message Ordering:
queue_options:
name: 'priority_queue'
flags: {x-max-priority: 10}
Memory Leaks:
unserialize() for untrusted data (security risk). Use json_decode() or a custom serializer.public function execute(array $message)
{
try {
// Process message
} finally {
$this->getChannel()->close();
}
}
Configuration Overrides:
# config/packages/old_sound_rabbit_mq.yaml
old_sound_rabbit_mq:
connections:
default:
host: '%env(RABBITMQ_HOST)%'
export RABBITMQ_HOST=prod-rabbitmq.example.com
Consumer Lifecycle:
get() if not handled properly. Use set_blocking(false) for non-blocking calls or implement a timeout:
$channel->basic_consume($consumerTag, 'queue', false, false, false, false, [$this, 'execute']);
if (!$channel->is_consuming()) {
$channel->basic_consume($consumerTag, 'queue', false, false, false, false, [$this, 'execute'], ['timeout' => 5]);
}
RabbitMQ Management Plugin:
rabbitmq-plugins enable rabbitmq_management) and access the UI at http://localhost:15672 (default credentials: guest/guest).Logging:
old_sound_rabbit_mq in config/packages/monolog.yaml:
handlers:
rabbitmq:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.rabbitmq.log"
level: debug
channels: ["old_sound_rabbit_mq"]
Consumer Debugging:
-v (verbose) flag:
php bin/console rabbitmq:consumer -v upload_picture_consumer
execute() to test error handling.Common Errors:
ConnectionException: Verify RabbitMQ server is running and credentials are correct.NotFoundException: Check if the exchange/queue exists and the consumer is bound correctly.AccessRefused: Ensure the user has permissions for the vhost (e.g., `rabbitmqctl set_permissions -p /How can I help you explore Laravel packages today?