tech.guitarrapc.cóm

Technical updates

.NET Core on Lambdaでテスト、ローカル実行、async/await、ロギングについて

さて、AWS Lambdaの続きです。

https://tech.guitarrapc.com/entry/2016/12/02/053001

Lambdaというかサーバーレスに限らず、ローカル実行ができるか、言語機能の対応状況、ログ確認方法は開発の基本となります。NuGetパッケージの対応状況や他を見る前にざっと確認しておきましょう。

テスト

新規プロジェクトとしてSimpleAsyncFunctionという名前で、SimpleAsyncFunctionで作成します。

with Testsを選ぶことで、xUnitによるテストプロジェクトが追加されます。あくまでもローカル実行ではなく、テストプロジェクトの追加であるということに気を付けてください。

前回同様、dotnet restoreをして新規プロジェクトのパッケージを復元したら、Test Explorerでテストを実行してみましょう。Empty Projectなので、全部大文字になることを期待していますので、適当に絶対に通らないテストも追加してみて失敗することを確認します。

https://gist.github.com/guitarrapc/a137c143ce8d1f880962d07f4066df97

通らなかったところを、Assert.NotEqual("hogemoge", upperCase);にすれば当然通りますね。*1

いたって普通のユニットテストと分かります。TestLambdaContextTestLambdaContext名前空間に存在しますが、いい感じで扱えそうですね。

ローカル実行

Node.jsにおいてローカルでイベント送信を検証するときには、_testdriver.jsを作っていましたね。*2

https://aws.amazon.com/jp/blogs/developer/aws-lambda-support-in-visual-studio/

https://aws.typepad.com/sajp/2015/03/aws-lambda-support-in-visual-studio.html

.NET Core版のLambdaは、単純なコンソールアプリです。そこで、project.jsonでbuildOptionsbuildOptionstrue にした上で、エントリポイントとして、buildOptionsクラスのbuildOptionsスタティックメソッドを用意してあげればokです。

https://gist.github.com/guitarrapc/be5fa6e7f38a7855f8aed2960e089158

Lambda内部の関数はローカル変数の状態が見えない

Program内はローカル変数もバッチリです。が、Lambda本体の関数においてはブレークポイントは貼れるもののローカル変数が見えません。Watch Windowで変数を見ようとするとerror CS0012: The type 'ILambdaContext' is defined in an assembly that is not referenced. You must add a reference to assembly 'Amazon.Lambda.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=885c28607f98e604'.となっています。

project.jsonでもAmazon.Lambda.Coreは参照しているのですが、何じゃろほい...。

async/await しているときの注意

AWS Lambdaは、async/awaitな関数でも呼べます。いいですね。とても嬉しいです。Loggerを組まない限りは落ちることなくローカル実行できています。

https://gist.github.com/guitarrapc/5bfb764f2efbc1d7441f9ad6eb901f94

ただ、後述のロガーを仕込んでおいてローカル実行で.Resultするとnullぽります。

System.NullReferenceException: Object reference not set to an instance of an object.

これはProgram.csのローカル実行時にnullではなくLambdaContextを渡せばokです。具体的には次の記事に書きました。

https://tech.guitarrapc.com/entry/2016/12/15/042111

async/await

サンプルがドキュメントにあります。

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/dotnet-programming-model-handler-types.html#dot-net-async

時間のかかる処理があるという前提で、Task.Delayを組んだメソッドを非同期に実行させるなら次のようになります。

https://gist.github.com/guitarrapc/f8a6279e8a4760c04a6dc2ff19f1fa3e

普通ですね。何も違和感なくつかえます。

ロギング

ロギングがどれだけスムーズかは開発効率に重大な影響を及ぼします。今回は最もシンプルでデフォルトで設定されているCloudWatch Logsへのログ出力を見てみます。

C# からのログ出力は、3つあるとドキュメントにあります。

https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/dotnet-logging.html

https://gist.github.com/guitarrapc/15de1d4363833f05f96997dd4b6e7014

確認してみると次の動作になります。

ロガー Lambdaコンソールでの出力 CloudWatch Logs への出力 Line出力の可否
Console.Write X O X
Console.WirteLine X O O
LambdaLogger.Log O O X
ILambdaContext.Logger.LogLine O O O
ILambdaContext.Logger.Log O O X

結果、私はILambdaContext.Logger.LogLineを使うことが多いです。AzureFunctionsと似てますね。

まとめ

テスト、ローカルデバッグ、async/await、ロギングと気になるポイントを見てみました。

なかなか素直な作りなので、安心ですね。.csxと違ってローカル実行に制限がほぼないのは素晴らしいです。

今回のサンプルもリポジトリに追加しておきました。

https://github.com/guitarrapc/AWSLambdaCSharpIntroduction

*1:意味はありませんがただの試しです

*2:_testdriver.jsではus-west-2リージョンがデフォルトは注意ですね