Hamizulfaiz

Tech Entrepreneur / System Builder

Bila Laravel Reverb Sampai, Tapi Event Tak Pernah Trigger

Published:

Updated:

fundamental Sistem

Aku baru-baru ini kena satu masalah yang agak annoying dengan Laravel Reverb.

Bukan sebab WebSocket tak connect.

Bukan sebab Reverb down.

Bukan sebab event tak dihantar.

Malah dalam Network tab, aku boleh nampak data WebSocket memang sampai.

Tapi UI tak react langsung.

Dalam kes ni, ada satu button Next yang bergantung kepada status workflow.

Bila workflow dah berubah, backend akan broadcast satu event. Frontend dengar event tersebut dan enable button Next.

Lebih kurang macam ini:

Backend
   ↓
Laravel Event
   ↓
Reverb
   ↓
WebSocket
   ↓
Laravel Echo
   ↓
Update UI
   ↓
Enable Next

Masalahnya, satu bahagian dalam chain ini nampak macam berfungsi, tapi sebenarnya tidak.


Event memang sampai

Ini yang buat debugging jadi sedikit mengelirukan.

Aku buka DevTools.

WebSocket connection ada.

Private channel pun subscribe.

Kemudian bila backend trigger event, nampak message masuk dalam Network tab.

Jadi pada pandangan pertama:

"Okay, Reverb dah jalan."

Tapi button masih disabled.

Frontend tak buat apa-apa.

Tak ada error yang jelas.

Tak ada exception.

Callback Echo pun macam tak pernah berlaku.

Ini bagi aku satu lesson yang penting:

WebSocket message sampai tidak bermaksud application event berjaya diterima oleh frontend.

Ada beberapa layer yang berbeza.

Event dispatched
      ↓
Reverb broadcast
      ↓
WebSocket frame received
      ↓
Echo match event name
      ↓
Echo callback
      ↓
UI state changes

Network tab mungkin hanya membuktikan satu benda:

WebSocket frame received

Ia tak membuktikan callback Echo telah execute.


broadcastAs() sebenarnya memainkan peranan

Event dia lebih kurang:

class WorkflowStatusUpdated implements ShouldBroadcast
{
    public function broadcastAs(): string
    {
        return 'workflow.status.updated';
    }
}

Kemudian aku listen daripada frontend.

Yang aku terlepas pandang ialah bila kita menggunakan custom broadcast name melalui broadcastAs(), cara Echo resolve nama event juga berubah.

Jadi listener perlu menggunakan . di depan:

Echo.private(`workflow.${workflowId}`)
    .listen('.workflow.status.updated', (event) => {
        // update UI
    })

Bukan:

.listen('workflow.status.updated', ...)

Dan bukan berdasarkan nama class:

.listen('WorkflowStatusUpdated', ...)

Ini benda kecil.

Satu character sahaja.

.

Tapi kesannya:

WebSocket      ✅
Reverb         ✅
Message        ✅
Echo listener  ❌
UI update      ❌

Dan sebab takde error yang obvious, kita boleh buang masa mencari masalah di tempat yang salah.


Lagi menarik bila ada polling

Sebelum aku betul-betul debug root cause, aku sebenarnya dah ada fallback.

Aku buat polling setiap 3 saat.

Logic dia lebih kurang:

             ┌── Reverb event ──→ update UI
Backend ─────┤
             └── Poll 3 sec ───→ update UI

Dari sudut production, idea ini nampak reasonable.

Kalau WebSocket bermasalah, polling boleh recover state.

Tapi masa development, dia hasilkan masalah lain.

Aku test workflow.

Tiba-tiba button Next enable.

Soalan pertama aku:

"Reverb dah trigger ke?"

Atau sebenarnya:

"Polling yang detect perubahan?"

Aku tak tahu.

Aku terpaksa letak console.log() di kedua-dua tempat.

.listen('.workflow.status.updated', () => {
    console.log('REVERB EVENT FIRED')

    // ...
})

Dan:

setInterval(() => {
    console.log('POLLING')

    // ...
}, 3000)

Barulah boleh nampak siapa sebenarnya yang mengubah state.

Pada masa itu aku sedar sesuatu.

Fallback yang sepatutnya membantu recovery sebenarnya sedang menyembunyikan bug yang kita cuba debug.


Jadi aku buang polling

Untuk sementara waktu, kita remove polling.

Aku nak satu source sahaja yang bertanggungjawab untuk perubahan tu.

Backend
   ↓
Reverb
   ↓
Echo
   ↓
UI

Kalau event berjaya, button enable.

Kalau event gagal, button kekal disabled.

Dan itu sebenarnya lebih bagus untuk debugging.

Sekarang aku boleh test dan terus nampak:

"Event memang tak trigger."

Kemudian aku pergi satu layer ke bawah.

WebSocket frame sampai.

Jadi bukan masalah connection.

Bukan masalah Reverb broadcast.

Kemudian aku tengok listener.

Dan akhirnya jumpa isu broadcastAs() tadi.

Benda yang nampak macam masalah Reverb sebenarnya berada pada event matching di Echo.


Realtime bukan semestinya source of truth

Lepas kena masalah ini, aku rasa ada satu architecture principle yang lebih penting.

Kalau button Next bergantung kepada business state, aku tak nak WebSocket jadi satu-satunya source of truth.

Reverb patut memberitahu:

"Something changed."

Kemudian frontend boleh fetch state sebenar.

Contohnya:

Reverb event
     ↓
Something changed
     ↓
GET latest workflow status
     ↓
Update UI

Jadi event tidak semestinya membawa seluruh logic untuk menentukan UI state.

Server tetap menjadi authority.

Ini juga membantu kalau event terlepas.

Contohnya user buka page selepas event sudah berlaku.

Kalau UI hanya bergantung kepada event:

Event berlaku
    ↓
User buka page
    ↓
Event sudah lepas
    ↓
UI tak tahu

Tapi kalau initial page load tetap fetch current state:

Page load
    ↓
GET current state
    ↓
Subscribe Reverb
    ↓
Future changes arrive instantly

Lebih predictable.


Production pula ada masalah lain

Dalam project lain, aku kena pula dengan isu Reverb masa deploy ke production.

Local semuanya okay.

Production tak.

Kali ini masalahnya lebih kepada configuration.

Yang membuatkan benda ini confusing ialah kita sebenarnya bercakap tentang dua dunia yang berbeza.

Ada server-side Reverb:

Reverb server
localhost:8080

Dan ada browser:

Browser
    ↓
wss://reverb.example.com

Browser tak semestinya patut connect menggunakan host yang sama dengan host yang digunakan oleh Reverb process secara internal.

Aku akhirnya asingkan konsep tersebut kepada:

REVERB_SERVER_HOST
REVERB_SERVER_PORT

untuk Reverb process itu sendiri,

dan public host untuk frontend/Echo:

REVERB_PUBLIC_HOST

atau nilai yang digunakan oleh Vite/Echo dalam setup project tersebut.

Mentaliti yang lebih mudah bagi aku ialah:

                 INTERNET
                    │
                    ▼
          reverb.example.com
                    │
              Reverse Proxy
                    │
                    ▼
             Reverb Server
             0.0.0.0:8080

Jangan terus anggap:

public host == internal server host

Sebab dua benda itu mewakili dua connection boundary yang berbeza.


Dan jangan panik bila nampak "Pusher"

Satu lagi benda yang boleh buat kita confused masa debug.

Reverb menggunakan Pusher protocol.

Jadi bila DevTools atau configuration nampak benda macam:

pusher
app_id
key
channel

jangan terus fikir:

"Kenapa dia pergi Pusher? Aku setup Reverb."

Reverb memang menggunakan Pusher-compatible protocol.

Architecture dia lebih kurang:

Laravel Echo
      ↓
Pusher JS protocol
      ↓
Laravel Reverb

Jadi kewujudan terminology Pusher tidak semestinya bermaksud request kita sedang menggunakan Pusher sebagai service.

Ini penting bila troubleshooting sebab kalau tidak, kita boleh mula debug benda yang sebenarnya bukan masalah.


Apa yang aku belajar daripada benda ini

Aku rasa masalah Reverb yang paling annoying bukan semestinya complexity WebSocket itu sendiri.

Kadang-kadang ia adalah layering.

Bila semua layer nampak hampir sama, kita mudah assume:

Message arrived
    =
Event handled

Padahal tidak.

Aku sekarang lebih suka debug realtime system dengan checkpoint yang jelas:

1. Event dispatched?
2. Reverb broadcast?
3. Channel subscribed?
4. WebSocket frame received?
5. Event name matched?
6. Echo callback executed?
7. UI state changed?

Setiap soalan mengecilkan search space.

Dan satu lagi:

Jangan letak fallback terlalu awal ketika sedang debug.

Polling, retry, optimistic UI, cached state dan fallback mechanism memang berguna untuk production.

Tapi masa mencari bug, benda-benda ini boleh membuat system nampak "okay" walaupun sebenarnya broken.

Kadang-kadang cara paling cepat untuk cari bug ialah dengan sengaja buang semua benda yang cuba menyelamatkan system.

Biarkan dia fail.

Bila dia fail dengan jelas, barulah senang nampak di mana sebenarnya ia putus.

Untuk Reverb pula, aku rasa mentaliti paling berguna ialah:

Transport ≠ Event routing ≠ UI state

WebSocket boleh healty.

Reverb boleh healthy.

Message boleh sampai.

Tapi Echo masih boleh tak trigger.

Dan kalau UI bergantung kepada event tersebut untuk membenarkan user teruskan workflow, satu character seperti . pun boleh menjadi beza antara:

workflow berjalan

dan

user stuck di button Next.
 

Laravel Reverb: Event Sampai Tapi Tak Trigger

Nak buat sistem?

Jom bincang untuk develop sistem yang custom untuk anda.

nak buat sistem bisnes? hubungi saya

Post Berkaitan

14 Sep 2026 Aku Dah Outgrow Laravel Valet
Aku Dah Outgrow Laravel Valet

Bila projek makin complex, setup Valet mula tak cukup. Ini workflow aku bila native development mula bertembung dengan Docker.

01 May 2026 Code Refactoring: Insurans Senyap Yang Selamatkan Bisnes
Code Refactoring: Insurans Senyap Yang Selamatkan Bisnes

Code refactoring bantu kurangkan tech debt, percepat debug, dan lindungi bisnes bila sistem live di production.

15 Apr 2026 Info Penting Founder Kena Beri Developer Sistem
Info Penting Founder Kena Beri Developer Sistem

Founder selalu gagal explain sistem pada developer. Ini checklist soalan & info penting supaya sistem siap cepat, tepat dan tak overbudget.

20 Feb 2026 Build vs Buy Software: Panduan Founder Untuk Elak Bazir Duit & Masa
Build vs Buy Software: Panduan Founder Untuk Elak Bazir Duit & Masa

Buat ke beli software? Artikel ringkas untuk founder & startup yang nak buat keputusan betul, elak burn duit, dan bina sistem yang boleh scale.

13 Feb 2026 From Manual to Automated: Sistem Klinik Dialisis Yang Potong Kerja Admin 70%
From Manual to Automated: Sistem Klinik Dialisis Yang Potong Kerja Admin 70%

Case study klinik dialisis tukar workflow manual kepada sistem automasi. Cara lindungi data pelanggan dan kurangkan beban kerja staf.

11 Feb 2026 Sistem Bukan Bina Sekali, Tinggal Sampai Mati
Sistem Bukan Bina Sekali, Tinggal Sampai Mati

Sistem bisnes bukan bina sekali dan tinggal selamanya. Tech berubah, security hole muncul, dan tanpa maintenance atau audit, sistem boleh menjatuhkan bisnes anda tanpa amaran.

10 Feb 2026 Sistem Terbaik Selalunya… Membosankan
Sistem Terbaik Selalunya… Membosankan

Kenapa sistem terbaik selalunya nampak boring? Artikel ini bongkar realiti founder yang lebih pentingkan UI berbanding sistem yang benar-benar bantu bisnes buat duit.

22 Jun 2018 Proses Membina Sistem: Bukan Sekadar Coding, Tapi Membina Cara Kerja
Proses Membina Sistem: Bukan Sekadar Coding, Tapi Membina Cara Kerja

Membina sistem bukan sekadar coding. Fahami proses mapping kerja, design database, hingga sistem stabil dan scalable untuk bisnes.

21 Jun 2018 Beza website syarikat dengan sistem
Beza website syarikat dengan sistem

Website biasa adalah berbeza dengan web bersistem

HAMIZULFAIZ