← 활용 사례

Reverb를 운영하지 않는 Laravel Echo

.env 값 몇 개만 바꾸면 이벤트, 채널, whisper, toOthers()가 그대로 동작합니다.

Laravel Broadcasting은 원래 Pusher 프로토콜을 쓰기 때문에, Laravel 앱은 기본 제공 pusher 연결 그대로 Hibira로 브로드캐스트를 보낼 수 있습니다. 이벤트, 채널 라우트, Echo 코드는 바뀌지 않습니다. 사라지는 것은 직접 운영해야 했던 WebSocket 서버입니다. 계속 실행되는 Reverb 프로세스, 서버 한 대를 넘어설 때 필요한 Redis, 스티키 로드 밸런싱, 그리고 밤에 그것을 지켜볼 사람.

사용자가 얻는 것

  • 주문 상태, 알림, 대시보드가 새로고침 없이 업데이트됩니다.
  • Echo의 join과 whisper로 "입력 중…" 표시와 온라인 목록이 있는 채팅.
  • 페이지를 여는 순간 최신 상태. 다음 이벤트가 올 때까지 빈 화면이 아닙니다.

사용하는 기능

  • pusher 연결과 pusher/pusher-php-server를 쓰는 Laravel Broadcasting.
  • 브라우저에서는 Laravel Echo와 pusher-js.
  • 직접 작성한 routes/channels.php로 인가하는 프라이빗 채널과 프레즌스 채널.
  • 클라이언트 이벤트(Echo whisper)와 보낸 사람 제외(toOthers()).
  • 마지막 이벤트를 새 구독자 모두에게 전달하는 캐시 채널(cache-).

1단계: Broadcasting을 Hibira로 향하게 하기

Laravel 11 이상에서는 broadcasting을 설치하고, 물어보면 Pusher를 고릅니다.

php artisan install:broadcasting
composer require pusher/pusher-php-server
npm install --save-dev laravel-echo pusher-js

그다음 .env에 연결을 설정합니다. 값은 앱 페이지에 있습니다.

BROADCAST_CONNECTION=pusher
PUSHER_APP_ID=YOUR_APP_ID
PUSHER_APP_KEY=YOUR_APP_KEY
PUSHER_APP_SECRET=YOUR_APP_SECRET
PUSHER_HOST=ws.hibira.io
PUSHER_PORT=443
PUSHER_SCHEME=https
PUSHER_APP_CLUSTER=ap

VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
VITE_PUSHER_HOST="${PUSHER_HOST}"
VITE_PUSHER_PORT="${PUSHER_PORT}"
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"

Laravel 10 이하에서는 BROADCAST_CONNECTION 대신 BROADCAST_DRIVER=pusher를 씁니다. 기본 config/broadcasting.php는 이미 호스트, 포트, 스킴을 Pusher 라이브러리에 넘깁니다. 직접 작성한 설정 파일이라면 options가 이 값을 읽는지 확인하세요. 그래야 pusher.com으로 연결하지 않습니다.

2단계: Echo 설정

// resources/js/echo.js
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;

window.Echo = new Echo({
  broadcaster: 'pusher',
  key: import.meta.env.VITE_PUSHER_APP_KEY,
  cluster: 'ap',
  wsHost: import.meta.env.VITE_PUSHER_HOST,
  wsPort: import.meta.env.VITE_PUSHER_PORT,
  wssPort: import.meta.env.VITE_PUSHER_PORT,
  forceTLS: import.meta.env.VITE_PUSHER_SCHEME === 'https',
  enabledTransports: ['ws', 'wss'],
});

3단계: 고객 한 명에게 이벤트 브로드캐스트

class OrderShipped implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct(public Order $order) {}

    public function broadcastOn(): array
    {
        return [new PrivateChannel('orders.'.$this->order->id)];
    }
}

// routes/channels.php
Broadcast::channel('orders.{id}', fn ($user, $id) => $user->orders()->whereKey($id)->exists());

// Wherever the order ships
OrderShipped::dispatch($order);
Echo.private(`orders.${orderId}`)
  .listen('OrderShipped', (e) => showStatus(e.order));

ShouldBroadcast 이벤트는 큐를 거치므로 워커(php artisan queue:work)가 실행 중이어야 합니다. 큐가 없는 프로젝트라면 ShouldBroadcastNow로 요청 중에 바로 발행하세요.

4단계: 프레즌스, whisper, toOthers()

Echo.join(`room.${roomId}`)
  .here((users) => online.set(users))
  .joining((user) => online.add(user))
  .leaving((user) => online.remove(user))
  .listen('MessageSent', (e) => messages.append(e.message))
  .listenForWhisper('typing', (e) => typing.show(e.name, 3000));
broadcast(new MessageSent($message))->toOthers();

whisper는 클라이언트 이벤트입니다. 앱 설정에서 Allow client events를 켜세요. toOthers()는 X-Socket-ID 헤더로 보낸 사람의 탭을 건너뛰며, Echo가 Axios 요청에 이 헤더를 자동으로 붙입니다. fetch를 쓴다면 'X-Socket-ID': Echo.socketId()를 직접 보내세요. 채팅방 전체는 채팅 사용 사례에 있습니다.

5단계: 새 페이지마다 최신 상태

이름이 cache-로 시작하는 채널에 브로드캐스트하면, 나중에 구독한 사람도 마지막 이벤트를 바로 받습니다(30분간 보관).

public function broadcastOn(): array
{
    return [new Channel('cache-scoreboard')];
}
Echo.channel('cache-scoreboard')
  .listen('ScoreUpdated', (e) => board.render(e.scores));

Echo.private('cache-orders.1')도 같은 방식으로 동작하며 private-cache-orders.1 채널이 됩니다.

Reverb나 다른 Pusher 호환 서비스에서 옮겨 오기

바뀌는 것은 .env 값뿐입니다. 이벤트, 채널 라우트, Echo 코드는 그대로이므로 환경을 하나씩 전환할 수 있고 되돌리기도 그만큼 쉽습니다. 확인할 항목은 마이그레이션 페이지에, 로그인하면 Laravel 가이드에 앱 값이 채워진 같은 설정이 있습니다.

팁

  • 환경(로컬, 스테이징, 프로덕션)마다 앱을 따로 만들면 테스트 이벤트가 실제 사용자에게 가지 않습니다.
  • 프레즌스 채널은 멤버가 최대 100명입니다. 더 큰 방은 대규모 시청자를 참고하세요.
  • 브로드캐스트는 몇 개의 브라우저가 받든 메시지 1건으로 계산되며, 전달과 프레즌스 업데이트는 무료입니다.