手機休眠時保持對話運作
Mythex 嘅代理可以就一個請求運作好幾分鐘,而你可能正用手機睇住佢工作。手機會鎖定、切換 app,亦會轉換網絡。兩個錯誤令呢個情況出問題。第一個,對話將每一次「頁面再次可見」嘅信號,都當成連線已經斷開嘅證明,然後不停循環,停喺「連線中…」。第二個,一部喺新對話嘅第一個回覆期間休眠嘅手機,醒返時只顯示回覆嘅頭幾段,要手動重新整理頁面先會恢復。兩個都已經修好。
對話點樣跟住運行中嘅回合
代理工作期間,對話會同我哋嘅伺服器保持一條串流:每個步驟(一個思考、一次工具呼叫、一段回覆)都會以事件形式抵達。如果串流斷開,對話會重新連線,而伺服器會從一個保存最近 120 秒事件嘅緩衝區中重播最近嘅事件。回合完結時,對話亦會向伺服器要求已儲存嘅歷史,並將它同已經顯示嘅內容對照。最後呢一步會捉住串流可能遺漏嘅嘢。
要喺冇嘢發生嘅時候分辨連線係活定死,伺服器每 15 秒就會發送一個細小嘅「ping」。
錯誤一:喚醒會殺死一條健康嘅串流
瀏覽器會話訴頁面,佢又再次可見了:例如切換分頁之後,或者螢幕解鎖之後。我哋將呢個當成檢查連線嘅提示,實際上,就係中止串流再重新連線,假設它喺隱藏期間已經死咗。
喺手機同嵌入式瀏覽器入面,呢啲事件出現嘅次數遠多過串流真正斷開嘅次數:每次切換分頁、每次解鎖,而喺某啲嵌入式瀏覽器入面,甚至每隔幾秒就出現一次。每次都會中止一條運作良好嘅串流。對話重新連線、重播、又被中止,最後停喺「連線中…」。然後佢會話回合已結束,而代理其實仍然喺度工作。
修正:睇串流係咪仍然有回應
而家對話會記錄每個專案嘅串流,最後一次收到任何東西嘅時間,包括事件同每 15 秒一次嘅 ping。「再次可見」嘅信號只會中止一條已經靜默咗 25 秒嘅串流:呢個時間比 ping 間隔加上一個慢速網絡跳轉都要長,所以一條仍然活躍嘅串流永遠唔會符合條件。測試會確認 ping 會被視為仍然存活嘅跡象,而剛剛才 ping 過嘅串流唔會被當成已死。
我哋從中得到嘅原則:頁面可見與否,講嘅係頁面,而唔係網絡連線。要直接問連線本身。
錯誤二:手機醒返後只見半個回覆
呢個問題,我哋可以喺 iOS 模擬器度每次都重現:
- 開始一個新對話,並送出一個需要一段時間嘅請求。
- 讓手機喺建構期間休眠。
- 等回合完結,並且兩分鐘嘅重播緩衝區已經過期之後,再返回。
對話顯示咗回覆嘅頭幾個區塊,並標記為已完成,然後就一直停留喺咁樣,直至你重新整理頁面。
原因
新對話喺第一則訊息建立對話串流(即係已儲存嘅對話)之前,係冇對話串流嘅。嗰個建立動作發生喺傳送函式內,而該函式之後先至執行;而傳送函式早已擷取咗對帳步驟,而嗰個步驟仍然以為冇對話串流。所以喺新對話第一個回合結束時,對帳看到冇對話串流,就靜靜咁返回,唔會要求任何嘢。
通常冇人會發現,因為串流本身已經將整個回合傳送咗。但係如果一部手機喺回合期間休眠,並喺 120 秒嘅重播緩衝區過期後先返回,佢就無法從串流取回遺漏嘅事件,而本應填補缺口嘅對帳,從來都冇執行過。
修正
- 傳送時會告訴對帳,該回合屬於邊個對話串流,所以新對話嘅第一個回合會同其他回合一樣被對帳。如果等待回覆期間你已經打開咗另一個對話,結果會被丟棄,唔會顯示喺錯誤嘅位置。
- 對帳失敗會重試。 手機喺連線欠佳時醒返,可能會發現回合已經完結,但卻未能取得它。呢個情況現在會被記住,而對話會喺分頁再次顯示或網絡恢復時再試一次。
- 「工作時間」要誠實。 每個回覆都會顯示代理工作咗幾耐。以前,如果分頁從未收到伺服器嘅回合完結訊息,它就會用自己嘅時鐘去填補這個數字,而嗰個時鐘由按下傳送計起,直到手機醒返為止,包括離開嘅時間。現在呢個數字會標記為估計值,並會喺歷史抵達後換成已儲存嘅實際時長。
我哋學到嘅嘢
- 喺用戶實際使用嘅裝置上,並按佢哋實際使用嘅方式測試。 兩個錯誤都藏喺「一條運作正常嘅串流」同「一部放喺口袋入面嘅手機」之間嘅縫隙裡面。
- 一個從來唔會運行嘅後備方案,根本唔算後備方案。 對帳步驟就係為咗捉住呢種情況而存在,卻靜靜咁跳過咗。
- 連復原步驟本身都要重試。 手機喺醒返嗰一刻,往往係連線最差嘅時候。
- 唔好將猜測當成事實顯示。 用錯誤時鐘計算出嘅時長,比完全冇更差;要標示清楚,或者換掉。
呢次工作亦順便整理咗一啲你喺回合運行期間會見到嘅嘢:shell 步驟會以做實際工作嘅指令標示,而唔係 cd;對話入面嘅截圖會保持頁面嘅左上角,並且符合欄位寬度;新項目亦會直接顯示系統生成嘅名稱,唔使重新整理。
如果你正為手機建構自己嘅 app,我哋嘅指南 點樣建構適合手機嘅網頁 app 同 原生 app 同漸進式網頁 app 嘅分別 會講基本概念。關於對話本身,可以睇對話文件。