5.5MBのPythonランタイムをブラウザ向けに配信しているチームが、直近のスプリント中に記録されたエラーの69%が、誤解を招く単一のタイトルに分類されており、そのうちの89%が実際にはネットワークタイムアウトであったことを発見しました。この誤った報告により、開発者は誤ったデバッグ作業に追われ、かなりの割合のユーザーがサイレントなダウンロード失敗に直面することになりました。これは、大きなアセットを同梱するあらゆるウェブアプリが直面しうる問題です。
ダッシュボードによる誤解
エラー追跡システムは、エラーが最初に発生したコードの場所に基づいて、インシデントを自動的にグループ化します。その結果生成されたタイトルは、ランタイムローダー内の単純なバグのように見えたため、スプリントの期間は、実際にはタイムアウトが発生しないコードパスを探し回ることに費やされてしまいました。チームが基礎となるメタデータをサンプリングしたところ、真の姿が明らかになりました。ほとんどの失敗はバグではなく、タイムアウトを引き起こしたネットワーク接続の停滞だったのです。
教訓: エラーのタイトルは利便性のためのものであり、診断結果ではありません。見出しが実際に何を表しているのかを確認するために、定期的に生データを掘り下げて調査してください。
ブラウザの接続APIがプレースホルダーを返していた
通信速度の遅いユーザーに5.5MBのダウンロードを強いるのを避けるため、開発者はブラウザの Network Information API (navigator.connection) を参照しました。しかし、このAPIは、初回訪問者全員に対して一律で1.7 Mbpsの帯域幅を報告していました。
ブラウザは、新しいユーザーに関する履歴データがない場合、デフォルト値を返します。そのデフォルト値はあくまでヒントであり、確定的な速度ではありません。新しいセッションごとに同じプレースホルダーが表示される場合は、そのAPIがまだそのユーザー層に対して適切に調整されていないことを示しています。
教訓: 全く変動しないネットワーク信号は、確定的な指標としてではなく、フォールバックとして扱ってください。
一時的なスナップショットは信頼できない
信頼できない帯域幅のヒントを破棄した後、チームはテストスイートで機能するように見えた別の信号に切り替えました。1回のテスト実行は成功しましたが、同じテストを3回繰り返すと、毎回失敗しました。ネットワーク速度は絶えず変動します。コードは一度だけスナップショットを取得して永続的な決定を下してしまい、その直後に接続状況が変わったとしても、そのまま処理を進めてしまっていたのです。
教訓: 変動する対象に対して、一度の読み取りに基づいて永続的なアクションを行わないでください。一度きりのポーリングではなく、変更イベントを購読(Subscribe)するようにしてください。
チームが実施した具体的な修正策
- 接続変更の購読:
navigator.connectionを一度だけ読み取るのではなく、changeイベントをリッスンし、ダウンロード中に帯域幅が低下または上昇した場合に反応するようにしました。 - 「進捗なし」ウォッチドッグの追加: タイマーを使用して、一定時間経過しても進捗がないリクエストを中断させ、ブラウザが再試行またはフォールバックを行えるようにしました。
- ダウンロード中のCDN切り替えを停止: 低速な回線で大きなファイルのソースを切り替えると、転送がゼロから再開され、それまでに受信したバイトが無駄になります。ダウンロード中は、最初に選択したCDNを最後まで使用するようにしました。
- 重いキャッシュ処理の遅延: 大量のデータをキャッシュに書き込むタスクは、ランタイムのロードが完了するまで後回しにし、クリティカルパスを短く保つようにしました。
もしダッシュボードが不気味なほど整ったデータを示しているなら、さらに深く掘り下げてください。ネットワークの測定値が全く動かないなら、それはプレースホルダーとして扱ってください。そして、一度のスナップショットが数メガバイトのダウンロードの成否を決定しているなら、それは蜃気楼に賭けているようなものです。そのような賭けは、ユーザーの信頼を損なうサイレントな失敗として現れます。それは、どれほど巧妙なコードを書いても、事後的に完全に修復できるものではありません。
