How to eliminate HTTP polling bottlenecks and stream instantaneous stock updates and order status changes using Laravel Echo, Redis pub/sub, and Soketi WebSockets.
In high-volume ERP and e-commerce platforms, multiple warehouse staff and sales reps update stock levels concurrently. Relying on HTTP polling to reflect stock adjustments causes server overhead and delayed inventory states.
Here is how we built a scalable event-driven architecture using Laravel WebSockets/Soketi, Redis Pub/Sub, and Laravel Echo + Vue 3 to push instantaneous inventory updates across tenant dashboards.
Whenever a sales order is completed or stock adjustment occurs, dispatch a broadcastable event implement ShouldBroadcastNow:
class=class="text-emerald-500 dark:text-emerald-400 font-medium">"text-slate-500 italic">// app/Events/StockLevelUpdatedEvent.php
namespace App\Events;
use App\Models\Product;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class StockLevelUpdatedEvent implements ShouldBroadcastNow
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public function __construct(
public Product $product,
public int $companyId
) {}
public function broadcastOn(): array
{
return [
new PrivateChannel('company.' . $this->companyId)
];
}
public function broadcastAs(): string
{
return 'stock.updated';
}
public function broadcastWith(): array
{
return [
'product_id' => $this->product->id,
'name' => $this->product->name,
'new_quantity' => $this->product->stock_quantity,
'updated_at' => now()->toIso8601String(),
];
}
}To ensure multi-tenant security, authorize channel access by matching the authenticated user's active company context:
class=class="text-emerald-500 dark:text-emerald-400 font-medium">"text-slate-500 italic">// routes/channels.php
use App\Models\User;
Broadcast::channel('company.{companyId}', function (User $user, int $companyId) {
return (int) $user->active_company_id === (int) $companyId;
});On the Vue 3 frontend, initialize Laravel Echo with WebSocket client credentials and listen to incoming event streams:
class=class="text-emerald-500 dark:text-emerald-400 font-medium">"text-slate-500 italic">// composables/useStockWebSocket.ts
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
import { onMounted, onUnmounted } from 'vue';
window.Pusher = Pusher;
export function useStockWebSocket(companyId: number, onStockUpdated: (data: any) => void) {
let echoInstance: Echo | null = null;
onMounted(() => {
echoInstance = new Echo({
broadcaster: 'reverb',
key: import.meta.env.VITE_REVERB_APP_KEY,
wsHost: import.meta.env.VITE_REVERB_HOST,
wsPort: import.meta.env.VITE_REVERB_PORT ?? 80,
wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
enabledTransports: ['ws', 'wss'],
});
echoInstance
.private(class="text-emerald-500 dark:text-emerald-400 font-medium">`company.${companyId}`)
.listen('.stock.updated', (eventData: any) => {
console.log('Real-time stock update received:', eventData);
onStockUpdated(eventData);
});
});
onUnmounted(() => {
if (echoInstance) {
echoInstance.leaveChannel(class="text-emerald-500 dark:text-emerald-400 font-medium">`company.${companyId}`);
}
});
}Replacing periodic HTTP polling with WebSocket event streaming reduced backend API load by 70% while guaranteeing sub-second stock synchronization across active team members.