CODE Polyglot / 備忘録

大きなコンテナの Lambda で、冷えた状態の最初の1回だけ子プロセスが10秒を超えた

10言語の実行環境を入れた大きなコンテナを Lambda で動かすと、しばらく使われていない状態からの最初の1回は、言語の実行環境の読み込みで子プロセスが遅くなります。子プロセスの待ち時間に余裕を持たせ、1つが時間切れでもほかの結果は返すようにしました。

起きたこと

ブラウザから送った入力を、10言語のプログラムに同時に渡して結果を返す Lambda を作りました(入口は Python。各言語は subprocess.run(..., timeout=10) で動かす)。作った直後の最初の呼び出しだけが、「時間内に終わりませんでした」(504)になりました。

再現の手順

コンテナを差し替えた直後(冷えた状態)に1回呼ぶと、どれかの言語が10秒を超えて 504 になりました(どの言語かは、全体を失敗にしていたので分かりません)。続けて2回呼んだときの、各言語の時間(ミリ秒)は次のとおりです。

呼び出し全体JavaScriptJavaC#KotlinRubyGoRust
2回目2.07秒1,8361,2801,4201,907928207
3回目0.56秒1813942594132372032

2回目でも、Node・Java・.NET・Kotlin は3回目の4〜10倍かかっています。

原因(推測を含む)

確かめたのは「冷えた状態の最初の1回だけ遅い」ことと、「実行環境の大きい言語ほど遅い」ことまでです。AWS の説明では、Lambda はコンテナイメージを使う部分から読み込むので、冷えた状態では Node・Java・.NET・Ruby の実行環境のファイルを初めて読む分だけ遅くなると考えられます(コンパイル済みの Go・Rust はほとんど変わらない)。10言語を同時に起動するので、読み込みも重なります。

直し方

  • 子プロセスの待ち時間を 10秒 → 20秒にした(Lambda の上限は30秒、API Gateway の上限は29秒なので、その内側)
  • 1つの言語が時間切れになっても、全体を失敗にせず、その言語だけに「時間切れ」の印を付けて、ほかの言語の結果は返すようにした
try:
    p = subprocess.run(cmd, capture_output=True, text=True, timeout=TIMEOUT)
except subprocess.TimeoutExpired:
    return {"lang": lang, "ok": False, "timeout": True}

確かめたこと

直したコンテナに差し替えた直後(冷えた状態)の最初の1回で、10言語すべてが正しい答えを返しました。続けて、正解表の33件×10言語=330件を本物の API に送り、すべて一致しました。