紀錄聊天室的線上人數、最後活動時間

這篇文章講的是我為聊天室做線上人數計算時考慮的點,
基本上就是:

  • AJAX + setInterval() = 沒效率、不可靠
  • WebSocket + WeakMap = WeakMap 不適合用在這個地方
  • WebSocket CloseEvent + Map = 連線時註冊到 Map,斷線時從 Map 退註冊,還行

這陣子都在忙公司直播網站的聊天室

其中一個重要的需求是紀錄每一分鐘的線上人數,以及每個人的觀看時間
之前的作法是透過 setInterval() 定期送 API 到後端更新 user->last_active_at 時間戳
然後後端可以找出 20 秒內有活動的人數,把這數字當成線上人數

這樣子做有兩個壞處:

  1. AJAX 帶來的運算開銷、雲端花費
  2. setInterval() 執行頻率不如預期的問題

第一點雲端花費的例子是 API Gateway 的計費方式就以 API 呼叫次數為主
第二點 setInterval() 的問題可以參考黑暗執行緒的「當心 setInterval 因瀏覽器節流模式嚴重失準


我們的聊天室其實一進去就會建立一個 WebSocket 連線直到活動結束
如果不好好利用這一點其實很可惜
(以前沒這麼做是因為我們曾採用 AppSync,無法這樣改,而且這東西真的讓人很痛苦)

剛好前陣子自發向上(欸)的我看了這篇「WeakMap and WeakSet(弱映射和弱集合)
其中便提到使用 WeakMap 的 Map 特性來紀錄使用者瀏覽次數,以及利用 Weak 特性在使用者離開時自動清除資料
這不禁讓我覺得 Weak 系列的資料結構也許可以跟 WebSocket 搭配的很好,讓我精準的紀錄使用者的觀看時間?

精準的意思是:
使用者一進入頁面(WebSocket 建立完成)就開始紀錄觀看時間,一離開頁面(WebSocket 中斷)就不再紀錄

只要 WeakRef deref() 回傳的不是 undefined,就視為使用者還在線上

不過試寫了之後發現不太對勁,因為數字對不上
後來發現可能是 Garbage Collection 導致的問題:也就是說,即使 WebSocket 早就斷線了,它的物件還是存在

WeakRef 的 MDN 文件上有這麼一句話

A WeakRef might never return undefined from deref, even if nothing strongly holds the target, because the garbage collector may never decide to reclaim the object.

他的意思應該可以解釋成:
即使沒有半個人 ref 到我的物件,但引擎老子說不 GC 就完全不 GC

笑死,感覺上了一課
最後還是乖乖的用 WebSocket.readyState 去判斷連線時間~
至於上線人數的部份,後來大概4改成 john

大概是這樣啦

日期

作者

留言

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *