こんにちは!ミライ工事ウェブエンジニアの @t4traw です。
つい先日、ミライ工事の写真台帳出力を2000枚以上に対応し、非同期出力にする事で生成時間も他の操作をして時間を有効に使えるようになりました!
今回はその開発をした時の技術的な経験を記録したものになります。
ミライ工事ではRailsを中心にバックエンドを構築していて、一部サブモジュールをLambda+Goで動かしています。
写真台帳や点検表の出力もLambda(と、API GatewayやDynamoDBなど)だったのですが、数千枚の写真台帳を出力しようとすると、どうがんばってもLambdaの実行時間(15分)の限界に達する問題が発生していました。
これは、ミライ工事の自由なレイアウトでエクセルとPDFが作れるという独自性ゆえの問題で、この特徴をもったまま一つの台帳でもっとたくさんの写真を扱えるようにして欲しいユーザーの声に応えるため、様々なアプローチを検討していました。
数千枚の写真台帳出力という課題に対し、複数のアプローチを検討しました。
などなどです。そして、最終的にStepFunctionsを選ぶ事にしました。その理由は、
1. 既存アーキテクチャとの親和性
2. 運用面のメリット
3. 開発工数の最小化
4. スケーラビリティ
開発期間の短縮と運用の安定性を考慮すると、現段階では最適な選択だったと判断しました。
LambdaとStepFunctionはInput/Outputで扱えるイベント(ペイロード)のサイズに制限があります。LambdaやAPIGatewayよりもStepFunctionsの制限の方が厳しく、2020年に増加されたものの、256KBになっています。
なので、まずはRails側でjsonをそのままbodyに入れてリクエストを投げるのではなく、S3にアップロードしたjsonのURLを渡すようにしました。
参考: AWS Step Functions はペイロードサイズを 256KB に増加
そして、それをAPIGatewayからStepFunctionsを起動するLambdaに渡し、StepFunctionsのInputとして設定します。
まず、最終的に以下のような全体像になりました。
StepFunction内では一部重い処理をMapステートで分割するなどして処理をしています。
開発当初はあまりステップ数を増やさず、必要に応じて増やしていく予定でしたが、最終的には結構処理を分割していくことにしました。そちらの方がエラー管理やリトライなども柔軟にできるようになったためです。
余談ですが、この開発中にStepFunctionsで変数が扱えるようになったのですが、Input/Output周りや他の対応などを変えるのが大変で使えていません😭 イベントデータのバケツリレー状態は早めに改善したいですね……。
StepFunctionという枠組みを使うことで、Mapステートによる並列実行、リトライやエラー処理の柔軟な設定、実行履歴の可視化などが簡単にできるようになりました。また、分岐もステップが可視化されて、非常に分かりやすくなりました。
一方で、開発の複雑さやコストは増加しました。GoはDockerに載せて動かしているのでECR、StepFunctions、DynamoDB、Lambda、S3をまとめてエミュレートするモノがなく、小さな関数はテストできるものの、結合テストはローカルで再現できないので、AWS上にdevelopment環境を作ってデプロイしてテストする必要があります。
コストも、StepFunctionのステップ数に応じて増えるので、コスト削減がシンプルにできません。具体的な金額を出せませんが、思ったより高いなぁと感じています。
今は2000枚以上を目標に構築してありますが、ステップの処理をさらに分割するなどすれば、もっとたくさんの写真を扱えるようになると思います。
また、StepFunctionsの変数対応なども進んでいるので、そちらも活用していきたいですね。
そして開発の効率化をもっと進めて、そちらは別の記事で共有できれば良いなと思っています。
音楽と珈琲とサウナと釣りが好きです🤟 Ruby, Go, Typescriptでいろいろ書いてます😃 WEB開発、WEBデザイン、自動化などをよくやっています🚀