HTTPで済む処理とブラウザが要る処理を見分ける
結論から言うと、薄い実装だけを見て取得方式を決めるな。全体の機能を確認してから、HTTPかブラウザかを選べ。
しろまえ殿は、複数のWebサイトを扱う取得基盤の移行で、まず原典のコードを読み込んだ。対象は34グループだった。
画面を描画するブラウザが必須なのは、最終的に2系統だけだった。残りの大半は、HTTPリクエストを直接送れば取得できる。
ただし、最初の調査結果はそのまま採用されなかった。
薄いファイルが判断を狂わせる
一部のグループには、特定機能だけを切り出した同期版ファイルがあった。そこだけ読むと、HTTPで取得できるように見える。
しろまえ殿は、クルーに本体側の実装範囲も確認させた。
すると、本体にはブラウザ操作を前提にした機能が残っていた。同期版の見た目だけで機械的に判定していたら、ブラウザ必須のグループをHTTP可と誤分類していた。
この確認で、ブラウザが必要なグループは一つ増えた。調査の途中で結論を訂正できたのは、本体と補助実装を分けて見たからだ。
非同期なのに処理が止まる
次に、Pythonの非同期テンプレートを確認した。
async defは、処理の待ち時間に別の仕事を進めるための宣言だ。ところが関数の中では、requestsのような同期HTTP処理をそのまま呼んでいた。
これではイベントループ(非同期処理を順番に動かす司令塔)が待ち続ける。見た目は非同期でも、実際には全体を止める。
たとえば、レジの担当者が「待ち時間に次の客をさばく」と言っておきながら、宅配便が届くまでレジを離れないようなものだ。
しろまえ殿は、同期I/O(外部応答を待つ処理)をasyncio.to_thread()で包む方針にした。これで、ブロッキングする呼び出しを別スレッドへ逃がせる。
対象のpull系関数を一つずつ点検し、全10関数を確認した。修正後はAST解析(Pythonコードの構造を調べる仕組み)で、全関数がasync defになっていることも確認した。
読者が移行するときの順番
最初に、原典の機能範囲を読む。補助版だけを見て判断しない。
次に、実地確認が必要なものだけを最小回数で試す。同じURLを何度も叩かず、取得結果を保存して以後はローカルで調べる。
非同期化では、関数宣言だけを変えない。同期ライブラリの呼び出し箇所まで確認する。
ブラウザが必要か迷ったら、HTTPで取得できるかではなく、対象機能全体をHTTPだけで再現できるかを基準にする。
しろまえ殿が最後に実体と構文の両方を確認したことで、量産前の判断表とテンプレートの欠陥が同時に整理された。地味な棚卸しだが、後続の手戻りを減らす効果は大きい。