cleancode/simple-bus-on-steroids
Installation:
composer require cleancode/simple-bus-on-steroids
Ensure simplebus/simple-bus and doctrine/dbal (or another DBAL-compatible package) are also installed.
Configuration: Publish the config file:
php artisan vendor:publish --provider="CleanCode\SimpleBusOnSteroids\SimpleBusOnSteroidsServiceProvider"
Update .env with your RabbitMQ and database settings (e.g., SIMPLE_BUS_ON_STEROIDS_* keys).
First Use Case:
use CleanCode\SimpleBusOnSteroids\Event\EventBus;
use CleanCode\SimpleBusOnSteroids\Event\Event;
$eventBus = app(EventBus::class);
$event = new Event('user.created', ['user_id' => 123]);
$eventBus->publish($event);
use CleanCode\SimpleBusOnSteroids\Event\EventSubscriber;
class UserCreatedSubscriber implements EventSubscriber
{
public function handle(Event $event): void
{
// Handle the event (e.g., send email, update analytics)
}
public static function subscribedTo(): string
{
return 'user.created';
}
}
Register the subscriber in config/simple_bus_on_steroids.php under subscribers.
Run the Async Worker:
php artisan simple-bus-on-steroids:work
This processes events from the database and pushes them to RabbitMQ.
Event Publishing with Transactions:
DB::transaction(function () use ($user, $eventBus) {
$user->save();
$eventBus->publish(new Event('user.created', ['user_id' => $user->id]));
});
Async Rabbit Pattern:
simple-bus-on-steroids:work command fetches events from the database and pushes them to RabbitMQ in batches.config/simple_bus_on_steroids.php:
'async_rabbit' => [
'batch_size' => 100,
'delay_seconds' => 1,
],
Handling Events with Retries and Dead Letters:
max_retries (default: 3), events are moved to a dead-letter queue (e.g., a separate RabbitMQ queue or database table).config/simple_bus_on_steroids.php:
'retry' => [
'delay_seconds' => 5,
'max_retries' => 3,
],
'dead_letter' => [
'queue' => 'dead_letter_events',
'table' => 'failed_events', // Optional: for DB-based dead letter
],
Event Correlation and Tracing:
event_id, correlation_id, parent_id, occurrence_time).$event = new Event('order.placed', ['order_id' => 456], [
'description' => 'User placed an order',
'correlation_id' => 'user-123-order-456',
]);
Subscriber Isolation:
class OrderPlacedSubscriber implements EventSubscriber
{
public function handle(Event $event): void
{
try {
// Business logic
} catch (\Exception $e) {
// Log the error (e.g., using Laravel's logger)
\Log::error("Failed to handle order.placed: " . $e->getMessage());
throw $e; // Will trigger retry logic
}
}
public static function subscribedTo(): string
{
return 'order.placed';
}
}
Laravel Integration:
EventBus to the container in AppServiceProvider:
public function register()
{
$this->app->bind(EventBus::class, function ($app) {
return new EventBus(
$app->make(Doctrine\DBAL\Connection::class),
$app->make(RabbitMQClient::class),
config('simple_bus_on_steroids')
);
});
}
Event-Sourcing:
description field to reconstruct event-sourced entities:
$event = new Event('user.updated', ['user_id' => 123], [
'description' => json_encode(['old_email' => 'old@example.com', 'new_email' => 'new@example.com']),
]);
Testing:
EventBus in tests:
$mockEventBus = Mockery::mock(EventBus::class);
$mockEventBus->shouldReceive('publish')->once();
$this->app->instance(EventBus::class, $mockEventBus);
Monitoring:
Database Locking:
batch_size small (e.g., 10-50) and ensure your database can handle the load.RabbitMQ Connection Issues:
Event Ordering:
correlation_id and parent_id to manually enforce relationships.correlation_id to group related events (e.g., all events for a single order).Dead-Letter Queue Overload:
Transaction Timeouts:
Check Event Status:
events table to see the status of published events:
SELECT * FROM events WHERE event_name = 'user.created' ORDER BY occurrence_time DESC;
status values like pending, processed, or failed.Log Subscriber Errors:
try {
// Subscriber logic
} catch (\Exception $e) {
\Log::error("Subscriber failed: " . $e->getMessage(), [
'event' => $event->getName(),
'payload' => $event->getPayload(),
]);
throw $e;
}
RabbitMQ Debugging:
http://localhost:15672) to inspect queues, messages, and consumer activity.Event Decoration:
event_id, correlation_id, and parent_id are set correctly for tracing. Use UUIDs for event_id:
$event = new Event('user.created', ['user_id' => 123], [
'event_id' => Str::uuid()->toString(),
'correlation_id' => 'user-123',
]);
Default Values:
config/simple_bus_on_steroids.php for:
retry.delay_seconds: Default is 5 seconds.retry.max_retries: Default is 3.dead_letter.queue: Must match your RabbitMQ dead-letter exchange/queue.Database Schema:
events, failed_events). Run migrations if they’re not present:
php artisan vendor:publish --provider="CleanCode\SimpleBusOnSteroids\Database\MigrationsServiceProvider"
php artisan migrate
Async Worker Command:
--once to processHow can I help you explore Laravel packages today?