Laravel Broadcasting dengan Redis dan Socket.IO

October 04, 2021

Pengantar

Laravel Broadcasting memungkinkan kita untuk sharing event yang sama (berikut datanya) antara server-side laravel dan client-side javascript. Salah satu contoh, Dengan Broadcasting, user dapat menerima notifikasi dari aplikasi tanpa harus me-refresh browser.

Pada kesempatan ini saya akan mencoba meng-aplikasikan Laravel Broadcasting dengan Redis dan Socket.IO.

Arsitektur

Arsitektur Laravel Broadcasting dengan Redis dan Socket.IO

Step 1 Laravel

Install fresh Laravel

composer create project --prefer-dist laravel/laravel laravelbroadcasting

Masuk directory project dan buat Event

cd laravelbroadcasting && php artisan make:event TestEvent

Supaya Event bisa broadcastable, tambahkan interface ShouldBroadcast dan edit fungsi broadcastOn menjadi return new Channel('test');

// app/Events/TestEvent.php

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

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        return new Channel('test');
    }
}

Tambahkan route untuk dispatch event

// routes/web.php
Route::get('test-event', function() {
    TestEvent::dispatch();
    return "OK";
});

Test route test-event di browser

http://127.0.0.1:8000/test-event

test-event Route

Check log di file storage/logs/laravel.log

[2021-10-04 11:46:53] local.INFO: Broadcasting [App\Events\TestEvent] on channels [test] with payload:
{
    "socket": null
}

Event masih broadcast ke log karena BROADCAST_DRIVER=log di .env.

Step 2 Queue

Install redis-server jika belum terinstall, dengan:

sudo apt install redis-server

update QUEUE_CONNECTION=sync menjadi QUEUE_CONNECTION=redis di file .env dan jalankan perintah:

php artisan queue:work

php artisan queue:work

Broadcast event sudah melewati queue.

Step 3 Redis

update BROADCAST_DRIVER=log menjadi BROADCAST_DRIVER=redis di file .env Lalu monitor event dengan:

redis-cli MONITOR

redis-cli monitor

Untuk sementara, broadcast event sudah melewati redis.

Step 4 Socket.IO Server

Install laravel-echo-server dengan menjalankan perintah:

sudo npm install -g laravel-echo-server

Membuat file konfigurasi laravel-echo-server.json dengan perintah

laravel-echo-server init

laravel-echo-server init

edit file config config/database.php

\\ config/database.php

....

'redis' => [

        'client' => env('REDIS_CLIENT', 'phpredis'),

        'options' => [
            'cluster' => env('REDIS_CLUSTER', 'redis'),
            'prefix' => '',
        ],

        ....

Jalankan perintah php artisan queue:work, lalu test dengan laravel-echo-server start

laravel-echo-server start

Sekarang, event berhasil melewati socket.io server.

Step 5 Socket.IO Client

Install package socket.io-client dan laravel-echo

npm install --save socket.io-client@2.4.0 laravel-echo@1.11.2

Tambah kode di resources/js/bootstrap.js

// resources/js/bootstrap.js

...
import Echo from "laravel-echo"
window.io = require('socket.io-client');

window.Echo = new Echo({
    broadcaster: 'socket.io',
    host: window.location.hostname + ':6001' // host laravel-echo-server
});

Jalan perintah npm install && npm run dev, lalu edit file resources/views/welcome.blade.php

// resources/views/welcome.blade.php

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="csrf-token" content="{{ csrf_token() }}">
        <title>Laravel</title>
    </head>
    <body>
        <h2>Welcome</h2>
    </body>
    <script src="{{ asset('js/app.js') }}"></script>
    <script>
        Echo.channel('test')
        .listen("TestEvent", e => {
            console.log(e)
        })
    </script>
</html>

Buka http://127.0.0.1:8000 dan http://127.0.0.1:8000/test-event di browser di tab yang berbeda.

browser 1

Jika berhasil, event akan muncul di console browser. Saya coba sisipkan data pada event

// app/Events/TestEvent.php

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

    public $data = 'Ini data event';

    ...

Sisipkan data

Private Channel

Jika ingin menggunakan private channel, ada beberapa file yang akan di config. Client yang ingin menerima event dari private channel diperlukan status authenticated.

Uncomment App\Providers\BroadcastServiceProvider di config/app.php, dan edit route channel di file routes/channels.php

// routes/channels.php

Broadcast::channel('test', function ($user) {
    return true;
});

Edit laravel echo script di resources/views/welcome.blade.php

// resources/views/welcome.blade.php

...
<script>
    Echo.private('test')
    .listen('TestEvent', e => {
        console.log(e)
    })
</script>

Edit app/Events/TestEvent.php

// app/Events/TestEvent.php

...
class TestEvent implements ShouldBroadcast
{
    ...
    public function broadcastOn()
    {
        return new PrivateChannel('test');
    }
}

Jika buka / di browser, maka akan muncul error log laravel-echo-server Client can not be authenticated, got HTTP status 403

Edit file app/Providers/AppServiceProvider.php

// app/Providers/AppServiceProvider.php

use App\User;
use Illuminate\Support\Facades\Auth;
...
class AppServiceProvider
{
  public function boot()
  {
    $user = User::factory()->make();
    Auth::login($user);
  }
}

Buka /test-event dan check log Queueu Worker, laravel-echo-server, dan console browser.

queue worker log Queue worker log

echo server log Laravel echo server log

browser console log

Jika berhasil, event akan muncul di console browser.


Profile picture

Written by Yogi Gilang Ramadhan who lives and works in Jawa Barat, ID. Building useful things. You should follow me on Twitter