Laravel Events and Listeners — Event-Driven Architecture That Scales Revenue
> cd .. / HUB_EDITORIALE
Sviluppo di siti web

Laravel Events and Listeners — Event-Driven Architecture That Scales Revenue

[2026-08-08] Author: Ing. Calogero Bono
> share
Zenithby Meteora Web The operating system for your business. Social, clients, bookings and invoices in one platform. Gyms, barbers, professionals. Discover Zenith Free demo · no card

Is your e-commerce going down every time a customer buys? Or worse, does the confirmation email arrive ten minutes later, when the user has already left? If your code handles everything inside the controller, you are paying for a problem with a name: synchronous, coupled architecture. At Meteora Web, we see it every day in the projects we take over. The solution, in Laravel, is called event-driven.

The idea is simple: when something important happens — an order, a payment, a user registration — your system should not do everything right there. It should say "this happened" and let other parts of the code react independently, maybe in a queue, maybe in real time. In this guide, we show how to set up Laravel Events, Listeners, and Broadcasting to build applications that do not freeze, do not lose data, and do not keep customers waiting.

Why does event-driven architecture change the game?

Think of a physical store. When a customer buys, the cashier does not run to restock the warehouse before charging. They record the sale, and other people — the warehouse worker, the accountant, marketing — react to the "sale recorded" event on their own. If the warehouse worker is busy, the sale does not block. That is how an application should work.

In Laravel, Events are classes that represent something that happened. Listeners are classes that react to those events. The controller, or the service, dispatches the event and does not know (and does not care) who is listening. This decoupling brings three concrete benefits:

  • Performance: heavy operations (email, notifications, updates) can go to the queue, without slowing down the response to the customer.
  • Maintainability: adding a new reaction (e.g., "send welcome coupon") does not touch the order code. Just add a listener.
  • Reliability: if a listener fails, the event has already been dispatched. You can retry, log, compensate. The main data is not lost.

We always think in terms of costs and returns. An event-driven architecture reduces development time for new features and maintenance costs. It is an investment that pays off, not an architect's whim.

Sponsored Protocol

How does an event work in Laravel?

An event is a class that holds the relevant data. For example, for an order:

// app/Events/OrderCreated.php
namespace App\Events;

use App\Models\Order;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class OrderCreated
{
    use Dispatchable, SerializesModels;

    public $order;

    public function __construct(Order $order)
    {
        $this->order = $order;
    }
}

The listener, on the other hand, is the class that does something with that data:

// app/Listeners/SendOrderConfirmation.php
namespace App\Listeners;

use App\Events\OrderCreated;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Facades\Mail;
use App\Mail\OrderConfirmation;

class SendOrderConfirmation implements ShouldQueue
{
    public function handle(OrderCreated $event)
    {
        Mail::to($event->order->customer_email)
            ->send(new OrderConfirmation($event->order));
    }
}

The ShouldQueue is the key: it sends the listener to the queue, so the HTTP response does not wait for the email. The customer receives the confirmation in seconds, but the server is not blocked.

To register the event-listener pair, you use the EventServiceProvider:

// app/Providers/EventServiceProvider.php
protected $listen = [
    OrderCreated::class => [
        SendOrderConfirmation::class,
        UpdateInventory::class,
        NotifyAdmin::class,
    ],
];

And to dispatch the event, from your controller or service:

use App\Events\OrderCreated;

OrderCreated::dispatch($order);

That is it. The controller knows nothing about email, inventory, or notifications. It did its job: it recorded the order and said "this happened." Everything else is reactive.

Sponsored Protocol

How to handle queued events without losing data?

The queue is the heart of event-driven in production. Without a queue, the event is just an abstraction. With a queue, it becomes a system that scales. But beware: a poorly configured queue is worse than no queue. Here are the critical points.

Configuring the queue and workers

In .env, you set the connection. We recommend Redis or database to start, RabbitMQ or SQS when volume grows.

QUEUE_CONNECTION=redis

Then start the worker:

php artisan queue:work

In production, use Supervisor to keep it alive. If the worker dies, events stay in the queue and are processed on restart. No data lost — if you have configured retries.

Retries and failures: when the listener goes wrong

A listener can fail: the email service is down, a field is null, a dependency does not respond. Laravel lets you define how many attempts and with what backoff:

public $tries = 5;
public $backoff = [10, 30, 60];

And in failed() you can log or notify. The point is: the order is safe, the event has been dispatched. The failure is local, not systemic. And with php artisan queue:retry all you re-run failed jobs after fixing the issue.

Common mistakes to avoid

  • Do not put too much logic in the listener: if a listener does too many things, coupling returns. Split into smaller listeners.
  • Ignoring failed jobs: check the failed_jobs table regularly. A listener that fails silently is a hidden bug.
  • Using the queue without testing: locally, with QUEUE_CONNECTION=sync, listeners run immediately. In production, with a queue, test with an active worker. The difference is huge.

Broadcasting: when the event must reach the browser in real time

So far, we have talked about internal server reactions. But there are events that must reach the client in real time: a notification, a status update, a message. Laravel Broadcasting does exactly that: it transmits the event via WebSocket to whoever is connected.

Sponsored Protocol

How broadcasting works with Laravel Reverb or Pusher

Laravel 11 introduced Reverb, a native WebSocket server, which you can run with php artisan reverb:start. Alternatively, Pusher is a cloud service. The configuration is similar:

BROADCAST_CONNECTION=reverb
REVERB_APP_ID=your-app-id
REVERB_APP_KEY=your-app-key
REVERB_APP_SECRET=your-app-secret
REVERB_HOST=127.0.0.1
REVERB_PORT=8080

Then create a broadcastable event:

// app/Events/OrderStatusChanged.php
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;

class OrderStatusChanged implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets;

    public $orderId;
    public $status;

    public function __construct($orderId, $status)
    {
        $this->orderId = $orderId;
        $this->status = $status;
    }

    public function broadcastOn()
    {
        return new Channel('orders.' . $this->orderId);
    }

    public function broadcastAs()
    {
        return 'status.updated';
    }
}

And on the frontend, with Echo:

import Echo from 'laravel-echo';
import Pusher from 'pusher-js';

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: 'your-app-key',
    wsHost: window.location.hostname,
    wsPort: 8080,
    forceTLS: false,
    enabledTransports: ['ws', 'wss'],
});

Echo.channel('orders.123')
    .listen('.status.updated', (e) => {
        console.log('Order status updated:', e.status);
        // Update the UI without reloading the page
    });

The result? The customer sees the order status change in real time, without refresh. For an e-commerce, this is the experience that makes the difference between a purchase and an abandonment.

Public and private channels

Do not broadcast sensitive data on public channels. For personal notifications, use PrivateChannel and define authorization in routes/channels.php:

Sponsored Protocol

Broadcast::channel('orders.{orderId}', function ($user, $orderId) {
    return $user->id === Order::find($orderId)->user_id;
});

This ensures that only the order owner receives the event. A flaw here would be a security disaster.

Where to put business logic: events, listeners, or services?

This is the question we always get. The answer is: it depends. But there is a practical rule we use:

  • Event: represents a completed fact. It contains no logic, only data.
  • Listener: reacts to the fact. It can call a service, but should not contain complex business logic.
  • Service: contains business logic. If an action has more than three steps, put it in a service and call it from the listener.

For example, the UpdateInventory listener should not calculate stock levels. It should call InventoryService::updateForOrder($order). This keeps the code testable and reusable.

How to test events and listeners without losing your mind?

Testing is where event-driven architecture shows its muscles. Laravel gives you tools to fake events and verify they are dispatched, without executing the listeners.

use App\Events\OrderCreated;
use Illuminate\Support\Facades\Event;

public function test_order_created_event_is_dispatched()
{
    Event::fake();

    // Perform the action that should dispatch the event
    $this->post('/orders', [...]);

    Event::assertDispatched(OrderCreated::class, function ($event) use ($order) {
        return $event->order->id === $order->id;
    });
}

And to test a listener in isolation, you can use Bus::fake() if the listener is queued, or directly call the handle() method with a fake event. The point is: with events, the test is deterministic. You do not have to wait for the queue to run, you do not have to simulate the email service. You verify that the event was dispatched with the right data, and that the listener does the right thing when invoked.

Sponsored Protocol

What design mistakes to avoid in event-driven?

Event-driven is not a magic wand. If you use it poorly, you create more problems than you solve. Here are the mistakes we see most often:

  • Too generic events: a UserUpdated event listened to by ten listeners, but no one knows why it was dispatched. Better to use specific events: UserEmailChanged, UserPasswordReset.
  • Listeners modifying the same data: if two listeners update the same field at different times, you create race conditions. Synchronize or split responsibilities.
  • Forgetting error handling: a listener that fails and is not retried is a bug. Always configure tries and backoff.
  • Not documenting events: in a team, if you do not know that OrderCreated exists and what it carries, you rewrite code that already exists. Document events like you do for APIs.

At Meteora Web, we have built proprietary platforms with this architecture. The difference shows when traffic grows: the system holds, queues drain, customers do not wait. It is the difference between an application that survives and one that scales.

In summary

Event-driven architecture in Laravel is not a luxury for big projects. It is a discipline that saves you time, money, and sleepless nights. Here are the immediate actions:

  • Identify critical actions in your domain (orders, payments, registrations) and turn them into events.
  • Move slow operations (email, notifications, integrations) into queued listeners with retries and backoff.
  • Set up broadcasting for real-time notifications, with private channels and authorization.
  • Write tests with Event::fake() for every event you dispatch. If it is not tested, it does not exist.
  • Document events for your team. An undocumented event is technical debt.

If you want to dive into the whole framework, start from our Laravel pillar. And if you have a project suffering from coupling and slowness, you know where to find us.

> share
Ing. Calogero Bono

> AUTHOR_EXTRACTED

Ing. Calogero Bono

Ingegnere informatico, fondatore di Meteora Web e Zenith OS. System administrator e progettista di piattaforme, app e CMS proprietari, con esperienza in sviluppo full-stack, marketing digitale ed ecosistema Google.
[ Read Full Dossier ]

> METEORA_WEB // DIGITAL AGENCY

We build the digital presence your business deserves.

Websites, social media, online advertising, e-commerce and high-performance hosting, engineered with method by computer engineers in Sciacca, for all of Italy.

> MW_JOURNAL

> READ_ALL()