ecotone/enqueue
Adapter layer between Ecotone and the Enqueue messaging abstraction. Usually installed via Ecotone transport packages (AMQP, Redis, SQS). Install directly only to build custom Enqueue-backed transports and integrate with Ecotone channels and consumers.
Installation:
ecotone/amqp-transport, ecotone/redis-transport). For direct use (custom transports):
composer require ecotone/enqueue
php-enqueue/enqueue (≥2.0) and a supported broker extension (e.g., ext-amqp, ext-redis).First Use Case:
use Ecotone\Attribute\CommandHandler;
use Ecotone\Command\CommandHandlerInterface;
#[CommandHandler]
class ProcessOrderCommandHandler implements CommandHandlerInterface
{
public function __invoke(ProcessOrderCommand $command): void
{
// Business logic (e.g., update inventory, send email)
}
}
Bus (integrated with Laravel’s service container):
use Ecotone\Bus\CommandBus;
$bus = app(CommandBus::class);
$bus->dispatch(new ProcessOrderCommand($orderId));
Configure a Transport:
use Ecotone\Transport\Redis\RedisTransport;
use Enqueue\Redis\RedisConnectionFactory;
$connectionFactory = new RedisConnectionFactory('redis://localhost');
$transport = new RedisTransport($connectionFactory);
Bus in Laravel’s AppServiceProvider:
public function register(): void
{
$this->app->bind(RedisTransport::class, fn() => new RedisTransport(
new RedisConnectionFactory(config('queue.redis.connection'))
));
}
Run Consumers:
ecotone/ecotone) or integrate with Laravel’s task scheduler:
ecotone:consume --transport=redis
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Ecotone\Bus\QueryBus;
class RunEcotoneConsumers extends Command
{
protected function execute(InputInterface $input, OutputInterface $output): int
{
$bus = app(QueryBus::class);
$bus->consume(); // Starts consuming messages
return 0;
}
}
Verify:
redis-cli for Redis queues).Where to Look First:
tests/ in the ecotone-dev repo for integration patterns.Job classes with Ecotone’s #[CommandHandler] or #[QueryHandler].
#[CommandHandler]
class SendWelcomeEmailCommandHandler
{
public function __invoke(SendWelcomeEmailCommand $command): void
{
Mail::to($command->email)->send(new WelcomeEmail($command->user));
}
}
$bus = app(CommandBus::class);
$bus->dispatch(new SendWelcomeEmailCommand($user->email));
use Illuminate\Support\Facades\Event;
Event::listen(UserRegistered::class, function ($event) {
$bus->dispatch(new SendWelcomeEmailCommand($event->user->email));
});
#[EventHandler] for CQRS or event sourcing.
#[EventHandler]
class HandleOrderPlacedEvent
{
public function __invoke(OrderPlacedEvent $event): void
{
// Update inventory, send notifications, etc.
}
}
Event system:
Event::dispatch(new OrderPlacedEvent($orderId));
EventBus directly:
$eventBus = app(EventBus::class);
$eventBus->publish(new OrderPlacedEvent($orderId));
use Ecotone\Saga\Saga;
#[Saga]
class OrderFulfillmentSaga
{
public function __invoke(OrderPlacedEvent $event): void
{
$this->bus->dispatch(new ReserveInventoryCommand($event->orderId));
$this->bus->dispatch(new ShipOrderCommand($event->orderId));
}
}
SagaBus:
$sagaBus = app(SagaBus::class);
$sagaBus->start(new OrderFulfillmentSaga(), $event);
use Ecotone\Outbox\Outbox;
class OrderService
{
public function placeOrder(OrderData $data)
{
DB::transaction(function () use ($data) {
$order = Order::create($data);
app(Outbox::class)->publish(new OrderPlacedEvent($order->id));
});
}
}
$outbox = new Outbox(new RedisTransport($connectionFactory));
$this->app->singleton(Outbox::class, fn() => $outbox);
use Ecotone\Transport\Transport;
use Enqueue\Client\Producer;
use Enqueue\Client\Consumer;
class StompTransport implements Transport
{
public function __construct(private Producer $producer, private Consumer $consumer) {}
public function produce($message): void
{
$this->producer->send($message);
}
public function consume(callable $callback): void
{
$this->consumer->consume($callback);
}
}
Bus:
$this->app->bind(StompTransport::class, fn() => new StompTransport(
new Producer(new StompConnection('stomp://localhost')),
new Consumer(new StompConnection('stomp://localhost'))
));
Bus and transports in AppServiceProvider:
use Ecotone\Bus\CommandBus;
use Ecotone\Transport\Redis\RedisTransport;
public function register(): void
{
$this->app->singleton(CommandBus::class, fn() => new CommandBus(
new RedisTransport(new RedisConnectionFactory(config('queue.redis.connection')))
));
}
use Illuminate\Console\Command;
use Ecotone\Bus\QueryBus;
class EcotoneWorker extends Command
{
protected $signature = 'ecotone:work';
protected $description = 'Run Ecotone message consumers';
public function handle(): void
{
$bus = app(QueryBus::class);
$bus->consume();
}
}
app/Console/Kernel.php:
protected function schedule(Schedule $schedule): void
{
$schedule->command('ecotone:work')->everyMinute();
}
use Illuminate\Contracts\Queue\Job as LaravelJob;
use Ecotone\Message\Message;
class LaravelJobToMessageConverter
{
public function convert(LaravelJob $job): Message
{
return new Message(
$job->payload(),
$job->getJobId()
);
}
}
How can I help you explore Laravel packages today?