edfa3ly-backend/rabbitmq-bundle-consumer-generator
Installation
composer require edfa3ly-backend/rabbitmq-bundle-consumer-generator
Ensure php-amqplib/rabbitmq-bundle is already installed (this package extends it).
Register the Bundle
Add to config/bundles.php:
return [
// ...
Edfa3ly\RabbitMQBundleConsumerGenerator\Edfa3lyRabbitMQBundleConsumerGeneratorBundle::class => ['all' => true],
];
First Use Case: Dynamic Consumer Creation
Inject GeneratorWrapper into a service (e.g., a command or event listener) and define a consumer:
use Edfa3ly\RabbitMQBundleConsumerGenerator\GeneratorWrapper;
use Edfa3ly\RabbitMQBundleConsumerGenerator\ConsumerSkeleton;
class CreateConsumersCommand
{
public function __construct(private GeneratorWrapper $wrapper) {}
public function handle()
{
$consumer = new ConsumerSkeleton();
$consumer->setName('order_processor')
->setQueueRoutingKeys(['order.created'])
->setExchangeType('fanout')
->setService('App\Services\OrderProcessorService');
$this->wrapper->generate($consumer, __DIR__.'/../config/rabbitmq/consumers');
}
}
Define Consumers Programmatically
Use ConsumerSkeleton to configure consumers dynamically (e.g., in a migration, command, or service bootstrapping):
$consumer = new ConsumerSkeleton();
$consumer->setName('user_notifier')
->setQueue('user_events')
->setExchange('notifications')
->setExchangeType('direct')
->setRoutingKeys(['user.registered', 'user.updated'])
->setService('App\Services\UserNotifier')
->setQos(10) // Prefetch count
->setAutoAck(false);
Generate YAML Config
Call GeneratorWrapper::generate() to write the consumer to your RabbitMQ config directory (default: config/rabbitmq/consumers/):
$this->wrapper->generate($consumer, $customPath = null);
order_processor.yml with the consumer’s configuration.Integration with RabbitMQ Bundle
The generated YAML adheres to php-amqplib/rabbitmq-bundle’s format. Ensure your config/rabbitmq.yaml includes:
consumers:
path: "%kernel.project_dir%/config/rabbitmq/consumers"
file_name_pattern: "%%name%%.yml"
Dynamic Consumer Lifecycle
post-install command).Environment-Specific Consumers
Use the GeneratorWrapper in a Bootstrap service to generate consumers conditionally:
if (app()->environment('production')) {
$this->wrapper->generate($highPriorityConsumer);
}
Consumer Templates
Create a base ConsumerSkeleton class with default values (e.g., autoAck: false) to avoid repetition:
class BaseConsumer extends ConsumerSkeleton
{
public function __construct()
{
$this->setAutoAck(false);
}
}
Event-Driven Generation
Trigger consumer generation on domain events (e.g., ConsumerAdded):
public function handle(ConsumerAdded $event)
{
$consumer = new ConsumerSkeleton();
$consumer->setName($event->name)->setService($event->service);
$this->wrapper->generate($consumer);
}
YAML Overwrite Risks
generate() overwrites existing YAML files without warning.if (!file_exists($path)) {
$this->wrapper->generate($consumer, $path);
}
Service Class Requirements
service field to point to a valid Laravel service container class. If the class doesn’t exist, the consumer fails silently.if (!class_exists($consumer->getService())) {
throw new \RuntimeException("Service {$consumer->getService()} not found.");
}
Queue/Exchange Name Conflicts
ConsumerSkeleton:
public function setQueue($name)
{
if (strpos($name, '.') !== false) {
throw new \InvalidArgumentException('Queue names cannot contain dots.');
}
$this->queue = $name;
return $this;
}
Bundle Compatibility
Verify Generated YAML After generation, validate the YAML matches expectations:
php artisan rabbitmq:validate
(If the command doesn’t exist, manually check config/rabbitmq/consumers/.)
Check RabbitMQ Logs If consumers aren’t working, inspect RabbitMQ server logs for connection/queue errors.
Enable Debugging
Temporarily enable debug: true in config/rabbitmq.yaml to log consumer generation:
consumers:
debug: true
Customize YAML Output
Extend ConsumerSkeleton to add custom fields or modify the YAML structure:
class CustomConsumer extends ConsumerSkeleton
{
private $customField;
public function setCustomField($value)
{
$this->customField = $value;
return $this;
}
public function getCustomField()
{
return $this->customField;
}
}
Then override the generator’s generate() method or use a custom template.
Add Consumer Metadata
Store additional metadata (e.g., created_at, environment) in the YAML:
$consumer->setMetadata(['environment' => app()->environment()]);
Hook into Generation
Subscribe to the rabbitmq.consumer.generated event (if the bundle supports it) or wrap GeneratorWrapper to add pre/post-generation logic:
$this->wrapper->generate($consumer, $path);
// Post-generation logic here
Support for Multiple Exchanges Extend the bundle to handle consumers with multiple exchanges/routing keys dynamically:
$consumer->setExchanges([
['name' => 'exchange1', 'type' => 'direct', 'routing_keys' => ['key1']],
['name' => 'exchange2', 'type' => 'fanout'],
]);
How can I help you explore Laravel packages today?