前回、Lambda Web Adapterを使ってSinatraアプリをAWS Lambdaで動かす話をしました。
今回は、Lambda Web Adapterを使っているコンテナでサーバーレスでタスクを実行する方法についてです。
タスクはrake taskを実行すればいいんでしょ?
はい。私も最初はそう思っておりました…。そのため、新たにLambdaを作って、同じDocker Imageを使うようにして、DockerのCMDを上書きしてrake taskを実行するようにしてみました。そしてLambda関数の詳細画面のテストタブから、テストを実施。
すると、期待通りのrake taskは実行されているんだけれど、テストが必ず失敗しました。原因は、『Lambda Web AdapterがHTTPのリクエストを期待して待っている間にrake taskが終了してexit 0が行われるため、Lambda Web Adapterからしたら勝手に終了させられた!と認識してしまうため』でした(長い)。
ということで、Lambda Web Adapterを含んでいるDockerコンテナでは、rake taskは使えません!!
Non-HTTP Event Triggers の存在を知る
まぁ、ちゃんと本家のREADMEを読めって話ですよ…。
Non-HTTP Event Triggersは、他のAWSのサービスからLambdaを呼び出すときに使うトリガーということですが、その受付口として、デフォルトで POST /events
のパスにアクセスすればいいとあります。
ということで、Sinatraで早速、POST /events
で処理を受け付けるようにして、rake taskで行っていた処理を移植しました。
前回の実装でAPI Gatewayから全てのリクエストはLambdaに転送するようにしてあるので、特に修正は不要。rake task用に作っていたLambda関数は削除しました。Docker Imageを更新してLambdaにデプロイし直した後、テストタブからLambda関数に対して POST /events
に向けてリクエストを実施。普通に処理されました🎉
EventBridge Schedulerから呼び出す
決まった時間帯に処理を行いたかったため、EventBridge Schedulerを定義してみました。cronのルールで対象のLambda関数を呼び出すようにして、JSONペイロードに POST /events
を表すものを記載してみました。パラメータはbody
に定義するので、適宜変えてください。
{ "version": "2.0", "routeKey": "POST /events", "rawPath": "/events", "rawQueryString": "", "headers": { "Content-Type": "application/x-www-form-urlencoded" }, "requestContext": { "http": { "method": "POST", "path": "/events" } }, "body": "name=taro&age=35", "isBase64Encoded": false }
また、決まった時間に処理を行うことよりも確実に処理を行える可能性を高めるほうを重視して、フレックスタイムウィンドウを15分に設定しました。
翌日、動作したか確認したところ、問題なく動作してたのでOK!!いやー、どんどん『サーバーレスチョットデキル』ようになってきています!✌️
サーバレスに移行後のコストメリットはあるのか?
まだ移行はしてないんですが、Railsを動かしているVPSの利用料が月額4,000円近くなのに対し、API Gateway + Lambda + DynamoDBに移行したら恐らく月額500~1,000円程度になるのでは?と思います。小さなコストカットではありますが、似たようなRailsアプリがちょこちょこあるので、どんどんこの構成に移植すれば、塵も積もればで年間で十数万のコスト削減になるかなと考えてます。あと金銭的なメリットもさることながら、サーバーレスであることが嬉しい。