Comment éliminer les goulets d'étranglement des requêtes HTTP et diffuser en direct les mouvements de stocks et les statuts de commandes avec Laravel Echo, Redis et Soketi.
Dans les ERP et plateformes e-commerce à fort trafic, plusieurs gestionnaires de stock et commerciaux modifient les niveaux de stock en simultané. Se reposer sur des requêtes HTTP régulières pour actualiser l'affichage engendre une surcharge serveur et des décalages d'inventaire.
Voici comment nous avons développé une architecture pilotée par les événements avec Laravel WebSockets/Soketi, Redis Pub/Sub et Laravel Echo + Vue 3 pour diffuser des mises à jour instantanées sur les tableaux de bord multi-locataires.
Lorsqu'une commande est validée ou qu'un ajustement de stock survient, déclenchez un événement implémentant 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(),
];
}
}Pour garantir la sécurité multi-tenant, autorisez l'accès au canal privé en vérifiant l'entreprise active de l'utilisateur authentifié :
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;
});Côté client Vue 3, initialisez Laravel Echo avec les identifiants WebSockets et écoutez les flux d'événements entrants :
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('Mise à jour de stock reçue:', eventData);
onStockUpdated(eventData);
});
});
onUnmounted(() => {
if (echoInstance) {
echoInstance.leaveChannel(class="text-emerald-500 dark:text-emerald-400 font-medium">`company.${companyId}`);
}
});
}Le remplacement des requêtes HTTP périodiques par la diffusion d'événements WebSockets a réduit la charge API du serveur de 70% tout en assurant une synchronisation parfaite des stocks en moins d'une seconde.