概要
- Webhookへ登録したCloud Run Functions
- 流れてきたデータを別途分析したいので、リクエストを受けてGCSへアップロードする処理を書いてた(非同期)
- 運用しつづけていると、何度か「GaxiosError: request to ... failed, reason: socket hang up at ...」というエラーログを確認してなんじゃろ?って調べたみた
- 発生頻度は8件/日ぐらい
原因
このエラーでググってみても原因わからず、Geminiと壁打ちしてたら仮説がでてきた
1. メイン関数が実行されると、まずGCSへ保存する関数が呼び出されます。
2. この関数は、内部でGCSへファイルを保存するNつの非同期関数(save...Log)を呼び出しますが、awaitを使って処理の完了を待ちません。コメントにも「あえて非同期にしている」と書かれている通り、これは意図的な実装です。
3. awaitがないため、メイン関数本体はGCSへの保存処理が終わるのを待たずに、すぐに次の処理に進み、最終的にreturn nullで終了します。
4. Cloud Functionsの観点では、メインの処理が終了したと見なされます。
5. その結果、まだバックグラウンドで実行中のGCSへのアップロード処理に対してCPUの割り当てが大幅に削減(スロットリング)されるか、インスタンス自体が終了処理に入ってしまいます。
6. CPUが制限された状態でネットワーク通信を行おうとすると、TLS接続の確立のような本来はミリ秒単位で終わる処理が極端に遅延し、タイムアウトします。これにより、「secure TLS connection was established の前に network socket disconnected」というエラーが発生します。
なるほど。と思って調べたらたしかにこれでした
解決案
いくつか複数ファイルをあげる仕様だったので、Promise.all + アップロードするメイン関数を同期処理にする。で解決しました
注意点
各アップロードは非同期にしたとはいえ、アップロードするデータ量次第ではそれなりに時間はかかるようになる(僕の場合は軽いJSONファイルなので1 ~ 3sぐらい)