Steven
Steven1 分で読める

ファイアウォールがWebSocketを塞ぐとき、リアルタイム文字起こしはどうなるか

企業ネットワークはHTTPSは通すくせに、WebSocketのアップグレードをこっそり殺すのが大好きです。それがリアルタイム文字起こしを黙って壊します。GeekBye v2.0.8は自動でピュアHTTPSトランスポートへフォールバックする — そしてそれを出荷する過程で、機能全体を無意味にしかねないバグが見つかりました。

文字起こし
ネットワーク
エンジニアリング
GeekByeリリース
ファイアウォールがWebSocketを塞ぐとき、リアルタイム文字起こしはどうなるか

企業ネットワークでリアルタイム文字起こしが失敗する、特定の、頭に来る失敗の仕方があります。Wi-Fiは問題ありません。HTTPSは動きます — どんなウェブサイトも読み込めます。なのにライブ文字起こしはただ…始まらず、なぜなのかは何も教えてくれません。

犯人は、通常のHTTPSトラフィックは許すのにWebSocketのアップグレード — HTTPS接続を、リアルタイム文字起こしが必要とする永続的な双方向チャネルへ変えるハンドシェイク — を塞ぐ種類の企業プロキシです。プロキシから見れば、WebSocketはネットワークの外へ抜ける監視外のトンネルに見えるので、殺します。あなたから見れば、文字起こしが黙って壊れているだけです。

GeekBye v2.0.8はまさにこのための自動フォールバックを追加しました — そしてそれを作る過程で、機能まるごとを何もしないものにしかねないバグが浮かび上がりました。

なぜリトライではなくフォールバックなのか

不安定なネットワークはすでに対処しています。セッションの途中で接続が切れれば、GeekByeはバックオフしながら再接続し、音声をバッファリングして何も失いません — それは別の機能で、AIノートテイカーはなぜ悪いWi-Fiで止まるのかで扱っています。

しかし塞がれたWebSocketは不安定な接続ではありません。WebSocketを拒否するプロキシに対して同じWebSocketをリトライしても、毎回、永遠に、同じように失敗します。唯一の直し方は別のトランスポート — プロキシがすでに許している素のHTTPSに見えるものです。

そこでv2.0.8は、同じ認証済みエンドポイント上でピュアHTTPSトランスポートへフォールバックします:

  • 下り(あなたに返ってくる文字起こし): server-sent events — プロキシには通常のストリーミングダウンロードに見える、長寿命のHTTPSレスポンス。
  • 上り(出ていくあなたの音声): バッチ化したPOSTリクエスト。それぞれがシーケンス番号付きの音声チャンクを運ぶので、ネットワークが順序を入れ替えてもサーバーが順番どおりに再構成できます。

永続的なソケットもなく、トンネルに見えるものもない — ただのHTTPSのリクエストとレスポンスです。プロキシがあなたにウェブサイトの利用を許すなら、これも許します。

死んだ機能を出荷しかけたバグ

ここが読む価値のある部分です。フォールバックは、WebSocket接続が遮断トランスポートのシグネチャとともに試行を使い果たしたときに発火するはずでした — すべての試行がアップグレードで失敗し、認証やクォータの問題はなく、少なくとも一つはプロキシ由来の拒否がある。WebSocketを塞ぐプロキシは通常、アップグレードにHTTP 403 Forbidden407で応じます。

問題はこうです: 私たちの接続コードにはすでに、403致命的な認証エラー — 停止し、ユーザーに提示し、リトライするなを意味するというルールがありました。ほとんどの場所ではそれは正しい。しかしそれは、遮断プロキシからの403 — フォールバックを発火させるべきまさにそのシグナル — が代わりに、フォールバックのロジックが走る前に致命的エラーとして投げられていた、ということでした。生の接続切断(1006クローズ)だけがフォールバックまで落ちてきていました。つまり機能は、まれなケースでは動き、本来の主対象である企業プロキシに対しては黙って失敗するはずだったのです。

これはプロダクションではなく、リリースを固めている最中に捕まえました。修正: WebSocketのアップグレード脚での403/407は今や回復可能として扱われ、接続ループが使い果たしてフォールバックへ落ちられるようになりました — 一方、本物の認証失敗(こちらは違う形で、アップグレード成功後に届く)は以前とまったく同じく、素早く失敗します。回帰テストが今この区別を固定しています: 遮断プロキシの403はフォールバックせねばならず、本物の認証403はしてはならない。

残りの堅牢化も同じ疑り深い筋で進めました: すべての上りPOSTにタイムアウトを付けて、リクエストは受け取るのに決して答えないプロキシが音声ストリームを止められないようにし、本物のサインインの問題がフォールバックの仕組みによって黙って覆い隠されることが決してないよう保証しました。

私たちは本物の敵対的プロキシに対してテストした

存在意義まるごとが敵対的なネットワークを生き延びることにある機能を、ユニットテストだけで検証することはできません — ユニットテストにはプロキシがありません。有効化する前に、企業プロキシがやることをそのままやるよう設定したローカルのリバースプロキシを通して、実際のアプリを走らせました: HTTPSは転送し、WebSocketのアップグレードを403で拒否する。

ログに残った軌跡が領収書です: 4回の塞がれたWebSocket試行、認識された使い果たしのシグネチャ、HTTPSトランスポートへの自動切り替え、そしてピュアHTTPS上での健全な96秒の文字起こしセッション — 66個の文字起こしセグメント、ドロップゼロ。フェイルオーバーが動くのは、フェイルオーバーする様子を私たちが見たからです。

三つの応用できる教訓

  1. 「不安定なWi-Fiで動く」と「敵対的なプロキシの背後で動く」は別々の保証だ。 一方は再接続を要し、もう一方は別のトランスポートを要する。両者を混同すると、企業ユーザーの一群まるごとを黙って壊したまま放置することになる。
  2. エラー分類は、あなた自身の機能を自分自身から隠しうる。 99%の場面で正しいルール(403 = 致命的な認証)が、この機能が存在する理由であるその1%に対してはまさに間違っていた。フォールバックを追加するときは、そのトリガー条件がそもそもフォールバックに到達できるのかを監査せよ。
  3. ハッピーパスだけでなく、敵をテストせよ。 「WebSocketを塞ぐプロキシを生き延びる」の唯一の誠実なテストは、WebSocketを塞ぐプロキシだ。私たちはそれを作った。

GeekBye v2.0.8はHTTPSフォールバックを、フラグでゲートし検証した上で出荷しました。それが隣り合う信頼性の仕事についてはAIノートテイカーはなぜ悪いWi-Fiで止まるのかを、このシリーズの近隣リリースについてはAIノートテイカーはなぜ会議の途中で録音を止めるのか(v2.0.9)とAI文字起こしはなぜ専門用語を聞き間違えるのか(v2.0.11)をご覧ください。

関連記事

アプリが自分自身にDDoSを仕掛けた日
Steven
Steven1 分で読める

アプリが自分自身にDDoSを仕掛けた日

起動時に一気に放たれた保留中アップロードの滞留が、あらゆるGeekByeクライアントを、自社サーバーへの小さなサービス拒否攻撃へと変えました。その修正 — そしてそれが私たちに作らせた接続生存性のはしご — は、v2が教えてくれた最も役立つことの一つです。

信頼性
ネットワーク
エンジニアリング
AI文字起こしはなぜ専門用語を聞き間違えるのか(そして私たちはどう直したか)
Steven
Steven1 分で読める

AI文字起こしはなぜ専門用語を聞き間違えるのか(そして私たちはどう直したか)

ライブセッションで「what is the pointer in C++」が「what is the point in life」と聞き取られました。そのトランスクリプトからGeekBye v2.0.11に至るまでの調査記録 — keytermバイアス、接続を切断していたタイミング競合、そして自分たちの修正が裏目に出た日の話です。

文字起こし
信頼性
エンジニアリング
画面録画がなぜ間違ったモニターを撮るのか(そして私たちの修正)
Steven
Steven1 分で読める

画面録画がなぜ間違ったモニターを撮るのか(そして私たちの修正)

デュアルモニター環境で、GeekByeはあなたがどちらの画面で作業していようとプライマリディスプレイを録画・スクリーンショットしていました。修正は小さな関数ひとつ — でもその最初のバージョンは間違っていて、コードレビューがその理由を見抜きました。

画面録画
マルチディスプレイ
エンジニアリング