Broadcasting: eventos em tempo real com Laravel Echo
1. Fundamentos do Broadcasting no Laravel
O broadcasting no Laravel permite que você transmita eventos do servidor para o frontend em tempo real usando WebSockets. Diferente do modelo tradicional de requisição-resposta HTTP, onde o cliente precisa fazer polling constante para verificar novidades, o broadcasting estabelece uma conexão persistente bidirecional entre servidor e cliente.
A arquitetura se divide em três componentes principais:
- Servidor WebSocket: responsável por gerenciar as conexões em tempo real (Pusher, Laravel Reverb, Soketi)
- Laravel Echo: biblioteca JavaScript que facilita a escuta de eventos no frontend
- Driver de broadcasting: configuração no Laravel que define qual servidor WebSocket utilizar
Para instalar o suporte a broadcasting no Laravel 11, utilize:
composer require laravel/reverb
Em seguida, publique os assets de configuração:
php artisan reverb:install
No arquivo .env, configure o driver de broadcasting:
BROADCAST_DRIVER=reverb
REVERB_APP_ID=seu-app-id
REVERB_APP_KEY=seu-app-key
REVERB_APP_SECRET=seu-app-secret
REVERB_HOST=localhost
REVERB_PORT=8080
2. Criando e Disparando Eventos Broadcast
Para criar um evento que pode ser transmitido, utilize o comando Artisan e implemente a interface ShouldBroadcast:
php artisan make:event MessageSent
A classe de evento deve estender ShouldBroadcast e definir o canal onde será transmitido:
<?php
namespace App\Events;
use App\Models\Message;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class MessageSent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public function __construct(
public Message $message
) {}
public function broadcastOn(): array
{
return [
new Channel('chat.'.$this->message->chat_id),
];
}
public function broadcastAs(): string
{
return 'message.sent';
}
}
Para disparar o evento, utilize o helper broadcast() ou a função event():
use App\Events\MessageSent;
// Disparo direto
broadcast(new MessageSent($message));
// Através de event() - útil para múltiplos listeners
event(new MessageSent($message));
// Com fila (recomendado para produção)
MessageSent::dispatch($message);
3. Autenticação de Canais Privados e Presença
Canais privados exigem que o usuário esteja autenticado para escutar os eventos. Configure as rotas de autorização em routes/channels.php:
use App\Models\User;
use App\Models\Chat;
Broadcast::channel('chat.{chatId}', function (User $user, int $chatId) {
return $user->chats()->where('chat_id', $chatId)->exists();
});
Para canais de presença, que rastreiam usuários conectados:
Broadcast::channel('presence.chat.{chatId}', function (User $user, int $chatId) {
if ($user->chats()->where('chat_id', $chatId)->exists()) {
return ['id' => $user->id, 'name' => $user->name];
}
});
A autorização pode utilizar Gates e Policies para lógicas mais complexas:
// app/Policies/ChatPolicy.php
public function join(User $user, Chat $chat): bool
{
return $chat->participants()->where('user_id', $user->id)->exists();
}
// routes/channels.php
Broadcast::channel('chat.{chat}', function (User $user, Chat $chat) {
return $user->can('join', $chat);
});
4. Laravel Echo no Frontend
No frontend, instale o Laravel Echo e o conector apropriado:
npm install --save-dev laravel-echo pusher-js
Configure o Echo no arquivo resources/js/bootstrap.js:
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
window.Echo = 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 ?? 8080,
wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
enabledTransports: ['ws', 'wss'],
});
Para escutar eventos:
// Escuta de evento em canal público
Echo.channel('chat.1')
.listen('.message.sent', (e) => {
console.log('Nova mensagem:', e.message);
});
// Escuta em canal privado
Echo.private('chat.1')
.listen('.message.sent', (e) => {
// Processar mensagem
});
// Notificações
Echo.private(`App.Models.User.${userId}`)
.notification((notification) => {
console.log('Notificação recebida:', notification);
});
// Whisper (mensagens temporárias como "digitando...")
Echo.private('chat.1')
.whisper('typing', { user: user.name });
5. Broadcasting em Canais Específicos
Canais Públicos
Qualquer usuário pode escutar sem autenticação:
// Evento
public function broadcastOn(): array
{
return [new Channel('public.news')];
}
// Frontend
Echo.channel('public.news')
.listen('.news.updated', (e) => {
// Atualizar feed de notícias
});
Canais Privados
Exigem autenticação e são ideais para dados sensíveis:
// Evento
public function broadcastOn(): array
{
return [new PrivateChannel('order.'.$this->order->user_id)];
}
// Frontend
Echo.private(`order.${userId}`)
.listen('.status.changed', (e) => {
// Atualizar status do pedido
});
Canais de Presença
Permitem rastrear usuários conectados:
// Frontend
const presenceChannel = Echo.join(`presence.chat.${chatId}`);
presenceChannel
.here((users) => {
console.log('Usuários atualmente conectados:', users);
})
.joining((user) => {
console.log(`${user.name} entrou no chat`);
})
.leaving((user) => {
console.log(`${user.name} saiu do chat`);
})
.listen('.message.sent', (e) => {
// Nova mensagem
});
6. Integração com Laravel Reverb
O Laravel Reverb é um servidor WebSocket nativo escalável. Para configurá-lo:
php artisan reverb:start
Para produção, utilize um gerenciador de processos como Supervisor:
[program:reverb]
command=php artisan reverb:start
process_name=%(program_name)s_%(process_num)02d
numprocs=1
autostart=true
autorestart=true
user=forge
Exemplo prático de chat em tempo real:
// app/Events/ChatMessage.php
class ChatMessage implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public function __construct(
public string $message,
public string $userName,
public int $chatId
) {}
public function broadcastOn(): array
{
return [new PresenceChannel('chat.'.$this->chatId)];
}
public function broadcastAs(): string
{
return 'chat.message';
}
}
// Controller
public function sendMessage(Request $request, Chat $chat)
{
$message = $chat->messages()->create([
'user_id' => auth()->id(),
'content' => $request->content,
]);
broadcast(new ChatMessage(
message: $message->content,
userName: auth()->user()->name,
chatId: $chat->id
))->toOthers();
return response()->json(['status' => 'sent']);
}
7. Boas Práticas e Depuração
Tratamento de Erros e Reconexão
Configure reconexão automática no Echo:
window.Echo = new Echo({
// ... outras configurações
reconnectionAttempts: 5,
reconnectionDelay: 1000,
});
Testes com PHPUnit
Teste o broadcasting sem depender do servidor WebSocket:
use Illuminate\Support\Facades\Event;
public function test_message_broadcast()
{
Event::fake();
$message = Message::factory()->create();
broadcast(new MessageSent($message));
Event::assertDispatched(MessageSent::class, function ($event) use ($message) {
return $event->message->id === $message->id;
});
}
Monitoramento
No Reverb, ative logs para depuração:
// config/reverb.php
'logging' => [
'channels' => ['stack'],
'level' => env('REVERB_LOG_LEVEL', 'debug'),
],
Monitore conexões ativas via dashboard do Reverb ou Pusher. Utilize ferramentas como Laravel Telescope para inspecionar eventos broadcast em desenvolvimento.
Lembre-se de sempre usar filas para eventos broadcast em produção, evitando que o servidor WebSocket bloqueie a resposta HTTP. Configure a fila padrão no arquivo .env:
QUEUE_CONNECTION=database
Referências
- Documentação oficial do Laravel Broadcasting — Guia completo sobre broadcasting, canais, eventos e configuração no Laravel 11
- Laravel Reverb - Documentação — Documentação oficial do servidor WebSocket nativo do Laravel, incluindo instalação e escalabilidade
- Laravel Echo - GitHub — Repositório oficial do Laravel Echo com exemplos de configuração para Pusher e Reverb
- Pusher Channels Documentation — Documentação do Pusher, provedor de WebSocket compatível com Laravel Echo
- Laravel Broadcasting com Reverb - Tutorial Prático — Artigo do Laravel News com exemplo completo de chat em tempo real usando Reverb e Echo
- Soketi - Servidor WebSocket Open Source — Alternativa open source ao Pusher, compatível com Laravel Echo e sem custos de licenciamento