手機休眠時讓對話保持連線
Mythex 的代理可以為一個請求工作好幾分鐘,而你很可能是用手機在看。手機會鎖定、切換應用程式、變更網路。兩個錯誤讓這種情況出了問題。其中一個是,對話把每一次「頁面重新可見」的訊號都當成連線已經中斷的證明,並不斷循環,最後停在「正在連線…」。另一個是,一個新對話的第一則回覆進行時手機正在休眠,回來後只看到前幾個片段,直到手動重新整理為止。這兩個問題都已修正。
對話如何追蹤進行中的回合
代理工作時,對話會保持一條來自我們伺服器的串流開啟:每個步驟(一個想法、一次工具呼叫、一段回覆片段)都會以事件的形式抵達。如果串流中斷,對話會重新連線,伺服器則會從一個保存最近 120 秒的緩衝區重播近期事件。回合結束時,對話也會向伺服器要求已保存的歷史,並把它與畫面上顯示的內容對帳。最後這一步會捕捉串流漏掉的任何內容。
在沒有任何事情發生時,為了判斷連線是活的還是已經斷了,伺服器每 15 秒會送出一個小小的「ping」。
錯誤一:喚醒會殺掉健康的串流
瀏覽器會告訴頁面它何時重新變得可見:切換分頁之後、螢幕解鎖之後。我們把這當成檢查連線的時機,實際上則是中止串流並重新連線,假設它在隱藏期間已經死掉。
在手機與嵌入式瀏覽器上,這些事件發生的頻率遠高於串流真正死掉的頻率:每次切換分頁、每次解鎖,有些嵌入式瀏覽器甚至每隔幾秒就會發生一次。每一次都會中止一個完全健康的串流。對話重新連線、重播、又被中止,最後停在「正在連線…」。接著它會顯示回合已結束,而代理其實仍在工作中。
修正方式:以串流是否仍在傳輸資料來判斷
現在對話會記錄每個專案的串流上一次收到任何資料的時間,包括事件與每 15 秒的 ping。「重新可見」的訊號只會在串流已經靜默 25 秒以上時才中止它:這比 ping 間隔加上一次較慢的網路跳轉還要長,因此健康的串流永遠不會符合條件。測試會檢查 ping 是否被視為存活的跡象,以及剛收到 ping 的串流是否不會被當成已經死掉。
我們從中得到的原則:頁面的可見性說明的是頁面,而不是網路連線。去問連線本身。
錯誤二:手機喚醒後只剩半則回覆
這個錯誤我們在 iOS 模擬器上每次都能重現:
- 開始一個新的對話,並送出一個需要一段時間的請求。
- 讓手機在建置期間休眠。
- 等回合結束後,且兩分鐘的重播緩衝區已經過期,再回來。
對話會顯示回覆的前幾個區塊,並標記為已完成,而且一直維持這樣,直到你重新整理頁面為止。
原因
新的對話在第一則訊息建立它之前,並沒有串接(也就是已保存的對話紀錄)。這個建立動作發生在傳送函式內部,而傳送函式在之前就已經擷取了對帳步驟,而那個步驟仍然認為沒有串接。因此,在新對話第一回合結束時,對帳看到沒有串接,就悄悄地返回,什麼都沒有要求。
通常沒有人會注意到,因為串流本來就已經傳送了整個回合。但是,如果手機在回合進行時休眠,並在 120 秒的重播緩衝區過期後才回來,它就無法從串流取得遺失的事件,而本來應該補上缺口的對帳,也從來沒有執行過。
修正方式
- 傳送時會告訴對帳步驟該回合屬於哪個串接,因此新對話的第一個回合會像其他回合一樣被對帳。如果等答案回來時你已經打開了另一個對話,結果會被丟棄,而不是顯示在錯誤的位置。
- 對帳失敗會重試。 手機在連線不良時喚醒,可能會發現回合已經結束,卻無法取得它。現在會記住這件事,當分頁再次顯示或網路恢復時,對話會再次嘗試。
- 「處理時間」顯示要誠實。 每則回覆都會顯示代理工作了多久。如果分頁從未收到伺服器的回合結束訊息,它過去會用自己的時鐘來補上這個數字,而該時鐘是從按下傳送開始計時,一直算到手機喚醒為止,包括離開的那段時間。現在這個數字會被標記為估計值,並在歷史資料送達後,改為已保存的實際時長。
我們的收穫
- 在人們實際使用的裝置上,以他們實際使用的方式測試。 這兩個錯誤都藏在「能正常運作的串流」與「放在口袋裡的手機」之間的縫隙中。
- 從未執行的備援機制不是備援。 對帳步驟原本就是為了捕捉這種情況,卻悄悄地跳過了它。
- 恢復機制本身也要重試。 手機喚醒的那一刻,往往也是其連線狀況最差的時候。
- 不要把猜測當成事實顯示。 從錯誤時鐘得來的時長,比沒有時長更糟;要嘛加以標示,要嘛替換掉。
這次工作也整理了你在回合執行時會看到的幾處細節:shell 步驟現在以實際完成工作的指令標示,而不是 cd;對話中的截圖會保留頁面的左上角並符合欄寬;新專案在不重新整理的情況下會取得它自動產生的名稱。
如果你要為手機建置自己的應用程式,我們的指南如何建置行動裝置友善的網頁應用程式與原生應用程式與漸進式網頁應用程式涵蓋了基礎知識。關於對話本身的更多資訊,請參閱對話文件。