※この記事はいつもよりマニアックな検証をしているので人を選びます
数日、公式メルマガよりServerless Framework V4が一般公開されたとの案内がきていました。実は先月くらいにアルファ版出てますよとHPに表示されていましたが、あまり時間が避けなかったので特に触れませんでした。
V4についての情報は去年の時点で発表されており、特に"有料化"という言葉が先走って少し話題になってしまった印象があります。
そんな中、最近投稿された記事にV4の目玉機能がいくつか紹介されていました。こちらが公式記事です。
中でもNative Typescript & Build SupportやTerraform Integrationといった気になる見出しがありますが、今回はRevamped Dev Modeという見出しのローカル環境で開発する時の機能が興味深かったのでご紹介です。
結論を言うとsls devはLambdaコードが即反映なのが凄いよってだけですが、長くだらだら書いていきます。
セットアップ
# v4インストール
npm i serverless -g
slsコマンド
→今回はAWS / Node.js / Express API with DynamoDBを選択。インストール後にnpm iを実行。
続いて何も設定を変えずsls devコマンドを実行、初回だけ数分かかりますがAWSの方を確認するとAPI Gateway〜Lambda〜DynamoDBが作成されています。
※元からsls loginしているので幾つかステップが簡略化されています
ローカルファイルをいじる
とりあえずHello Worldくらい出したいので初期状態のhandler.jsに追記します。
app.get('/', async (req, res) => {
res.json({
message: 'Hello, World'
})
})
そして何気なく、先ほど作成されたAPI Gatewayのエンドポイントをブラウザで開いてみると
あれ、デプロイしてないのにLambdaのコードが変わっていますよ🤔
sls devのコンソール出力を見てもホットリロードのような意味合いのログは一切出ていません。コードを編集してから即反映されたので、バックグランドでひっそりとデプロイされたという線もなさそうです。こういう得体が知れない挙動は実に面白いですね。
先ほどの公式の記事を読んでみると
Start a Dev Mode session with serverless dev, and your live AWS Lambda functions will redirect events to your local code for processing. The response from your local code is then sent back to the live Lambda function.
と記載されています。
英語の理解力がないせいか、Lambdaからローカルのコードを取得しているような説明に思えます。ここら辺はDeepLを持ってしても解釈がはっきりしないのが悔しいところですw
sls devコマンドがもたらす変化を調べる
まずはsls devコマンドを停止してみます。
停止してしまえば自動的にデプロイ?されることがなくなるだけで、最後に反映されたコードが最新になるだろうと予想していましたが、全然違いました。
sls devを再実行するか、sls deployでデプロイする必要があるようです。ローカルPCのアプリケーションが動いてるかどうかで、クラウド上のAPIの結果が変わるなんて謎が深まります。
次にLambdaの中身です。
もし実は超速でコードが都度デプロイされているとしたらこのコードが更新されているはずですが、最終更新日時をみる限りやっぱり違います。
slsのソースコードを読む
ここまで来たら徹底的に。Serverless Frameworkのソースコードを落とします。
そして先ほどsls devを停止した時に出ていた↓の文言を文字列検索
Dev Mode Disconnected: This AWS Lambda function is instrumented with Serverless Framework's Dev Mode but the Dev Mode session is no longer active. Run `serverless dev` to reconnect, or `serverless deploy` to remove Dev Mode's instrumentation and restore the original code.
↓意外とそのままハードコードされていました。
https://github.com/serverless/serverless/blob/main/lib/plugins/aws/dev/shim.js#L114
このファイルの上部に気になる一文を発見。
import iot from 'aws-iot-device-sdk'
AWSのIoTのサービスですね。そしてiotを使っているコードを探すと・・
const device = new iot.device({
protocol: 'wss',
host: process.env.SLS_IOT_ENDPOINT,
})
おおお、Webソケット・・・!
ということはLambda側にWebソケットを使っているような痕跡があるはず、と改めて色々探すと環境変数SLS_IOT_ENDPOINTにAWS IoTのデバイスデータエンドポイントが設定されていました。加えて、圧縮されたLambdaコードからwssとかconnectionとかそれっぽい記述を発見。
ここまでの情報をまとめると、下図のような構成をイメージしました。
ただ、ランタイムの部分が少しモヤっとしていてローカルに書いたLambdaコードがAWS上で動いているのか、ローカルで動いているのか確証を持てないので確かめます。
sls devを実行した時に~/.aws/credentialsのdefaultを参照しているので、これにDynamoDBのみ拒否するポリシーをアタッチします。
そしてローカルのLambdaにDynamoDBの操作を書きます。疎通確認なのでこんな感じに。
これを実行したところ、ちゃんと処理が成功しました。
続いてLambdaの方に設定されている実行ロールにDynamoDBを拒否するポリシーをアタッチして、再度実行します。
するとAccessDefinedのエラーが発生したようで、APIのレスポンス結果はcatchを通りました。ただし・・Lambda内で実行したconsole.logはCloud WatchではなくローカルPCのターミナルに出力されています。
うーーん🤯
→ここがどうもよく分からなかったのでChatGPTに尋ねたところ、stdoutを使って制御しているのではという結論に。serverless側のコードにも記載があります。ということはローカルのコードからCloudWatchに出力させるようにもハックも可能・・?いやもういいか・・。
まとめ
まあ何はともあれローカル環境の開発が快適になったことは間違いないことで、待ち時間が少ないので開発効率は上がります。
なぜここに注目したのかというと、最近やっているサーバレスのプロジェクトで1つのAPIの応答時間が5〜10秒くらいかかっていて、同じAWSでサーバレスを使っていてもこうも違うものか・・という何とも言えない気持ちになったからです。
長くなったので終わり( ´Д`)y━・~~