MENU

1つのLambdaに全部詰め込むのはアンチパターンだった

1つのLambdaに全部詰め込むのはアンチパターンだったことを説明する画像

おはようございます、YASUです。

CodePipelineの回で「司会者・調理担当・配膳担当」という役割分担の話をしましたが、今日紹介するStep Functionsも、似た発想の「指揮者」的なサービスでした。複数のLambda関数をどう連携させるか、という部分を整理します。

目次

結論

1つのLambda関数に全部の処理を詰め込むのは、AWS公式ドキュメントでも「アンチパターン」として明記されていました。Step Functionsは、処理を小さなLambda関数に分割し、その実行順序や分岐、エラー処理をまとめて管理してくれる「ワークフローの指揮者」でした。

なぜ1つのLambdaに全部詰め込むのがダメなのか

AWSの公式ドキュメントでは、複数のタスクを管理したり、再試行ロジックを実装したり、分岐ロジックを含んだりするLambda関数は「アンチパターン」だとはっきり書かれています。代わりに、それぞれが単一のタスクだけを行う複数のLambda関数を用意し、Step Functionsでその流れ全体を管理することが推奨されています。

例えば「注文処理」を考えてみます。

1. 注文内容の確認
2. 在庫レベルのチェック
3. 支払いの処理
4. 請求書の生成

これを1つの巨大なLambda関数にまとめて書くと、途中でエラーが起きた時にどこで失敗したか追いにくく、一部の処理だけ直したい時もコード全体を触る必要が出てきます。Step Functionsを使えば、この4つをそれぞれ独立したLambda関数として作り、その実行順序だけをStep Functions側で管理できます。

ステートマシンという考え方

Step Functionsでは、この「処理の流れ」を「ステートマシン」と呼ばれる形式で定義します。JSONベースの設定で、こんなイメージです。

{
  "StartAt": "注文内容の確認",
  "States": {
    "注文内容の確認": {
      "Type": "Task",
      "Resource": "Lambda関数のARN",
      "Next": "在庫レベルのチェック"
    },
    "在庫レベルのチェック": {
      "Type": "Task",
      "Resource": "Lambda関数のARN",
      "Next": "支払いの処理"
    }
  }
}

「次に何をするか(Next)」を順番に繋げていくだけで、複雑な処理の流れを視覚的にも、設定的にも管理できるようになります。

単なる「順番通りに実行する」だけではない

Step Functionsが便利なのは、単純な一直線の処理だけでなく、条件分岐やループ、待機といった、より複雑な制御もできる点です。

  • Choice(選択):条件によって、次に進む先を分岐させる
  • Wait(待機):指定した時間まで処理を待たせる
  • Pass(通過):値をそのまま次に渡したり、固定のデータを出力したりする

これらを組み合わせれば、「在庫がなければキャンセル処理に分岐する」「支払い確認が取れるまで数分待ってから次に進む」といった、実務でよくある複雑な業務フローも表現できます。

エラー処理も、Step Functions側に任せられる

個人的に一番「なるほど」と思ったのがこの部分です。Step Functionsのステートマシンに含まれるLambda関数の実行が失敗すると、その時点でステートマシン全体の実行が止まってしまいます。そのため、Lambda関数を含むステートマシンでは、リトライ処理やエラーのキャッチ処理をあらかじめ実装しておく必要があるとされています。

これまでLambda単体で「エラーが起きたらどうするか」をコードの中で書く必要がありましたが、Step Functionsを使えば、「このタスクが失敗したら、何回まで自動で再試行するか」「それでも失敗したら、どの処理に進むか」といったルールを、個々のLambdaのコードではなく、ステートマシンの定義側でまとめて管理できます。

LambdaからStep Functionsを呼び出す、2つの方法

調べていて気づいたのが、Lambda関数の呼び出し方にも種類がある、という点でした。

  • 同期呼び出し(RequestResponse):Lambda関数が結果を返すまで、Step Functionsが待つ
  • 非同期呼び出し(Event):結果を待たずに次の処理へ進む

デフォルトは同期呼び出しで、多くの場合はこれで問題ありませんが、「結果を待たずに次々と処理を投げたい」という場面では非同期呼び出しを選ぶ、という使い分けがあるようです。この違いを意識していないと、想定と違うタイミングで次の処理が走ってしまう、という事故につながりそうです。

CodePipelineとの共通点

前回のCodePipelineは「ビルド→デプロイ」という開発の流れを管理する指揮者でしたが、Step Functionsは「アプリケーションの業務処理」という、また別のレイヤーの流れを管理する指揮者です。どちらも「個々の作業は専門の担当に任せ、全体の順序と流れだけを管理する」という、同じ設計思想でできているのだと感じました。

まとめ

  • 1つのLambda関数に全部の処理を詰め込むのはアンチパターンとされている
  • Step Functionsは、複数のLambda関数の実行順序・分岐・エラー処理をまとめて管理する
  • Choice(分岐)、Wait(待機)など、複雑な制御も組み合わせられる
  • リトライやエラーのキャッチは、個々のLambdaではなくステートマシン側で管理できる
  • 同期呼び出しと非同期呼び出しの違いを意識しないと、想定外のタイミングで処理が進んでしまうことがある

DVAは本当に難しいと感じる日が続いていますが、1つずつサービスの役割を整理していくと、少しずつ全体像が繋がってきている気がします。それでは、また明日!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次