📖

脱Lambdaを目指して。運用負荷削減に向けたStep Functions中心の「ほぼ」コードレスアーキテクチャ

に公開

社内で稼働していたいくつかの通知系システムを、AWS Lambda から AWS Step Functions の構成に移行しました。
今回はその経緯と、実際に組んでみてどうだったかを共有します!

背景と課題

元々、以下のブログで紹介したような「ZennやQiitaの技術トレンド」や「AWSコスト」をLarkに通知する仕組みを AWS Lambda で運用していました。

https://ma-vericks.com/blog/lark-trend-notice/
https://ma-vericks.com/blog/aws-cost-post-lark/

今回、新たに「勤怠システムのトークン自動更新」の実装が必要になり、当初はこちらも Lambda で作ろうと考えていました。

しかし、アーキテクチャを検討する中で 「長期的な運用コスト」 について改めて考えました。
Lambda は非常に手軽ですが、長期運用していると数年おきに必ず ランタイム(Node.jsなど)のバージョンアップ対応 が発生します。

「今後、機能が増えていっても、この保守コストをかけ続けるのか……?」

そう考え、開発チームのリソースを「保守」ではなく「機能開発」に集中させるためにも、「ランタイム管理を極力しなくて済む、よりマネージドな構成」 として Step Functions の導入を提案し、実装を進めることになりました。

構築したアーキテクチャ

前述した「勤怠トークンの自動更新」の構成は以下のようになっています!
月1回のトリガーには Amazon EventBridge Scheduler(EB Scheduler) を採用し、認証情報の管理には Systems Manager Parameter Store を使用しています。

Step Functions を中心(ハブ)として、各サービスを以下のように連携させています。

  1. EB Scheduler: 月1回のトリガーで Step Functions を起動。
  2. Parameter Store: 認証情報を SDK Integration で取得・更新。
  3. Attendance API: HTTP Endpoint で外部勤怠システムのトークン更新APIを叩く。
  4. SSM Automation: 次回実行日時を EventBridge Scheduler に反映するために経由(後述)。

この処理を含め、全体では以下の機能をStep Functions を中心(ハブ)とした基盤で実装しました。

  1. 勤怠トークンの自動更新(新規)
  2. プロジェクト毎の稼働実績通知(移行)
  3. 工数入力漏れの検知通知(移行)
  4. Zenn・Qiita技術トレンド情報の取得(移行)
  5. AWSコスト情報の取得(移行)
  6. 祝日判定(新規:休日は通知をスキップ)
  7. Larkへの通知
  8. +その他、内部処理用の機能

例えば、「Zenn・Qiita技術トレンド情報の取得」 のフローは以下のような構成になっています!
ここでは、後述する 「XMLパース用のLambda」 が組み込まれています。

Step Functions が HTTP Endpoint で RSS を取得し、記事情報を整形して Lark に通知する流れです。Qiita記事情報は Lambda で JSON に変換しています。

これらをすべて Lambda で個別に実装・運用していたら、関数の管理だけで手一杯になっていたと思います。

こだわったポイント:脱Lambda(HTTP Endpoint & SDK Integration)

Step Functions を採用した最大の理由は、コードを書く量を減らすこと です。
外部API(Lark, 勤怠システム)へのリクエストには HTTP Endpoint 機能を使用し、AWSサービス間の連携には SDK Integration を活用しました。これにより、単純なAPIコールのためだけに Lambda を管理する必要がなくなりました。

技術的な壁と工夫

実装にあたり、いくつか工夫が必要なポイントがありました。

1. XMLパース問題(Lambdaの最小利用)

情報の取得元が XML形式 の場合があり、Step Functions の組み込み関数だけではパースが困難でした。
そのため、ここだけは「XMLを受け取ってJSONに変換する」役割の極小 Lambda 関数を用意しています。
ロジックが単純な変換のみであれば、将来的なランタイム更新の影響も最小限で済むという判断です。

2. JSONataの記述のクセ(学習コスト)

Step Functions の中でデータのフィルタリングや計算を行うために JSONata を活用しました。
これのおかげで、複雑な条件分岐や日時計算(例:次回の実行予定日の算出など)も Lambda を書かずに実現できたのですが、記述のクセが強く、最初は習得に苦労しました。

解決策として、基本的には AI(ChatGPT等)に「このJSONをこう変換したい」と投げてコードを生成してもらう ので作っていました。
また、生成されたコードが正しいかどうかは、Step Functions コンソールの 「ステートのテスト」機能 を使い、実際の入出力を確認しながらトライアンドエラーを繰り返して実装しました。

(今思えば、JSONata Exerciser などのオンラインツールを使って手軽に検証すれば、もっと効率的だったかもしれません……!)

慣れるまでは大変ですが、使いこなせば「痒いところに手が届く」強力な機能です。

3. Schedulerの自動更新(SSM Automationの活用)

「勤怠トークンの更新」は月1回の定期実行ですが、次回実行日時を動的に変更する必要がありました。
前述の JSONata を使って次回日時を算出したのですが、Step Functions の SDK Integration から直接 EventBridge Scheduler の実行日時を更新するモジュールが提供されていませんでした。

そこで、Systems Manager Automation を経由させる構成にしました。Step Functions から Automation をキックし、そこから Scheduler を更新することで、スムーズな連携を実現しています。

まとめ

  • ランタイム管理からの解放: ビジネスロジックの多くを Step Functions のステートに移譲したことで、ランタイム(Node.js等)のバージョンアップの保守コストを軽減しました。
  • フローの可視化: 処理の流れが図として見えるため、どこでエラーが起きているかが直感的に分かりやすくなりました。
  • 適材適所: 無理にノーコードにこだわらず、XMLパースはLambda、複雑なAWS操作はSSM Automationなど、適材適所でサービスを組み合わせるのが重要でした。

既存の Lambda のメンテナンスコストが気になっている方は、ぜひ Step Functions の HTTP Endpoint などを試してみてください!

マーベリックスのテックブログ

Discussion