tech.guitarrapc.cóm

Technical updates

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

さて、AWS Lambda の続きです。

tech.guitarrapc.com

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

目次

テスト

新規プロジェクトとしてSimpleAsyncFunctionという名前で、AWS Lambda Project with Tests (.NET Core)で作成します。

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

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

gist.github.com

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

いたって普通の xUnit テストと分かります。TestLambdaContextAmazon.Lambda.TestUtilities 名前空間に存在しますが、いい感じで扱えそうですね。

ローカル実行

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

aws.typepad.com

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

gist.github.com

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 を組まない限りは落ちることなくローカル実行できています。

gist.github.com

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

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

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

tech.guitarrapc.com

async/await

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

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

gist.github.com

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

ロギング

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

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

gist.github.com

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

ロガー 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 と違ってローカル実行に制限がほぼないのが素晴らしいです。

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

github.com

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

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

.NET Core on AWS Lambda がリリースされました

今年は非常にうれしいことが Azure と AWS 両方でありました。Azure Functions と .NET Core on AWS Lambda です。

これまで多くの AWS Lambda関数 (Node.js) と Azure Functions (C#) を書いてきましたがこれでようやく AWS Lambda に完全に寄せることができます。

早速 AWS Lambda で C# (.NET Core) を触ってみましょう。

目次

Lambda 上は Java と同じく dll をアップロード

Node と違い、Java 同様のdll を zip で固めてアップロードとなります。そのため、Lambda の画面でコードを直接触ることはできません。

ここは Azure Functions と違い直接コード修正にはなりませんね。ただし大事なのは、.NET Core をビルドした結果を挙げるという点です。Azure Functions ですぐに出会って今でも困るのが、「共通コードを参照した場合にローカルビルドを通せなくなるケース」や「.csx のためインテリセンスが非常に貧弱」という問題があります。*1

DLLをビルドしてアップロードということは、ローカル挙動が安定して、コンパイル、ビルドも安定するので個人的には十分に許容、嬉しいポインとのです。*2

C# (.NET Core) でコードを書いてみる

記事作成の現時点では AWS Document がないので、手探りで見てみましょう。ドキュメントが公開されたので参考にどうぞ。

環境は Windows 10 Pro + Visual Studio 2015 Enterprise です。

.NET Core 環境を用意する

まずは .NET Core の最新版をインストールします。手順通りにやっていきましょう。

Download .NET (Linux, macOS, and Windows)

インストール中...。

5分未満で完了すると思います。

Visual Studio Integration

AWS は Visual Studio Integration がかなり進んでいます。リソース管理にとどまらず、Node.js の Lambda 関数も書いています。

Lambda を C# (.NET Core) でVisual Studio で書くため、最新版の AWS SDK for .NET をダウンロード、インストールしましょう。インストール後に新規プロジェクト > Templates > Visual C# > AWS Lambda というのが新しくできています。

4つプロジェクトがありますが、今回はシンプルに関数を作ってローカルビルド > アップロードという流れでやるため「AWS Lambda Project (.NET Core)」 を使ってみましょう。

プロジェクト種別 説明
AWS Lambda Project (.NET Core) A project for creating a AWS Lambda Functions using .NET Core
AWS Lambda Project with Tests (.NET Core) A project for creating a AWS Lambda Functions using .NET Core
AWS Serverless Project (.NET Core) An AWS Serverless application uses the power of AWS Lmabda and AWS CloudFormation to build a cloud-enabled serverless application
AWS Serverless Project with Tests (.NET Core) An AWS Serverless application uses the power of AWS Lmabda and AWS CloudFormation to build a cloud-enabled serverless application

BluePrint の選択

4つのひな形が提示されています。今回は単純な Empty Function を作ってみます。

余談ですが、もし.NET Core のセットアップを忘れて、AWS Lambda Project を作ろうとすると次のエラーが出て作れないので注意です。この場合、前述した.NET Core の最新をインストールしてから、再度 Lambda プロジェクトを作ってみましょう。

もしも project.json のパッケージ復元でエラーが生じる場合

AWS Lambda (.NET Core) のプロジェクトを作って project.json でエラーが出る場合があるようです。*3

この場合、Amazon* とつくパッケージが解決できていない場合は、直接 nuget パッケージをインストールすればok です。例えば次のproject.json なら dotnet restore でパッケージを復元しましょう。*4

{
  "version": "1.0.0-*",
  "buildOptions": {
  },

  "dependencies": {
    "Microsoft.NETCore.App": {
      "type": "platform",
      "version": "1.0.1"
    },
    "Amazon.Lambda.Core": "1.0.0",
    "Amazon.Lambda.Serialization.Json": "1.0.0",
    "Amazon.Lambda.Tools": "1.0.0-preview1"
  },

  "tools": {
    "Amazon.Lambda.Tools": "1.0.0-preview1"
  },

  "frameworks": {
    "netcoreapp1.0": {
      "imports": "dnxcore50"
    }
  }
}

このコマンドを Package Management Console で実行でもパッケージは復元できます。*5

Install-Package Amazon.Lambda.Tools -Pre
Install-Package Amazon.Lambda.Core
Install-Package Amazon.Lambda.Serialization.Json

解決されれば、project.json のエラーが消えて、Function.cs もエラーが出ていないはずです。

この状態で何も編集せずビルドが通れば準備完了です。

サンプルコードの記述

雑に Console.WriteLine だけ追加してちょっとだけいじってみます。


[https://gist.github.com/guitarrapc/e21578a8c777993e97dae62e7f03ac8e:embed:cite]

アップロード

残念ながら今日発表された CodeBuild はC#をサポートしていません。

Build Environment – Language / runtime environment (Android, Java, Python, Ruby, Go, Node.js, or Docker).

AWS CodeBuild – Fully Managed Build Service | AWS News Blog

CI のことは次回以降にして、ローカルでビルドしてアップロードしてみましょう。

Node.js と同様に、「アップロードする対象のプロジェクトを右クリック -> Publish to AWS Lambda」 します。

資格情報などをいい感じにして

IAM Role に 必要な権限のロールを割り当てます。今回はただの実行なので lambda_exec_role でok です。

メモリは、いったんデフォルトのままで行きますが、Java と似た傾向と予想されます。性能に関しても後日確認してみましょう。

acro-engineer.hatenablog.com

ではUploadしてみてください。うまくいくと、Lambdaの画面を AWS Console を開かずに VS でFunction画面が開いてくれます。Event Source などもここにあるので、事実上のローカルからの直接実行です。

実行

そのまま Visula Studio から Invoke するか、AWS Console で実行してみましょう。

このとき、Node.js の時のように json でイベントを記述すると自動的にデシリアライズされてしまいエラーが発生してしまいます。

{
  "errorType": "JsonReaderException",
  "errorMessage": "Unexpected character encountered while parsing value: {. Path '', line 1, position 1.",
  "stackTrace": [
    "at Newtonsoft.Json.JsonTextReader.ReadStringValue(ReadType readType)",
    "at Newtonsoft.Json.JsonTextReader.ReadAsString()",
    "at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadForType(JsonReader reader, JsonContract contract, Boolean hasConverter)",
    "at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)",
    "at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)",
    "at Newtonsoft.Json.JsonSerializer.Deserialize[T](JsonReader reader)",
    "at lambda_method(Closure , Stream , Stream , ContextInfo )"
  ]
}

今回は、受ける引数を string としているので、"hogemoge" というストリングを送るようにします。うまく Response にかえって来ましたね。

任意のクラスを受けて実行する

次は string ではなく任意のクラスを用意して、外部から来た JSON を受けられるようにします。

想定する JSON は次のフォーマットです。

{"Str":"hogehoge","StrArray":["hoge","huga","foo"]}

対応するクラスは次の通りです。

public class SampleClass
{
    public string Str { get; set; }
    public string[] StrArray { get; set; }
}

ということで全体

gist.github.com

実行してみるとうまく取れていますね。

まとめ

まずは Hello World でした。次は Azure Functions で書いた処理をサクサク Lambda にもってきて紹介します。

今回の実装を含めて、AWS Lambda .NET Core (C#) の実装サンプルはリポジトリにあげていくのでよろしければどうぞ。

github.com

*1:個人的に C# を好んでいるのがインテリセンス強さなので、かなり嬉しくない副作用です。

*2:もちろん直接編集できる方がうれしいですが、副作用大きすぎるしむしろこれでいいです。

*3:わたしとか

*4:Private NuGet リポジトリを登録していたりすると dotnet restore に失敗するようです

*5:こちらなら Private NuGet リポジトリを登録していても影響ありません

Anagram check in C#

There are no chance of me to write Anagram check in C#.

Anagram - Wikipedia

Let's see some article posted.

blog.agile.esm.co.jp

It says he met anagram question with code interview and answer was as follows.

def anagram(s1, s2)
  s1.chars.sort == s2.chars.sort
end

Let's try in C#.

Contents

Enumerable.Except

First, I thought it's not good to use Sort for performance issue, and imagine to use Enumerable.Except.

Enumerable.Except Method (System.Linq) | Microsoft Learn

But soon I forgive it. Except will be worth when duplicate character is accepted but may take too much check if no allowed. You can see #7 failed with "aba == bab" was true!

gist.github.com

Same issue will happen with Enumerable.All.

https://msdn.microsoft.com/en-us/library/bb548541(v=vs.100).aspx

gist.github.com

O(n log n) : Sort with Enumerable.SequenceEqual

May be one of the easiest way is sort array then check. Let's use Enumerable.SequenceEqual() to sorted array.

Enumerable.SequenceEqual Method (System.Linq) | Microsoft Learn

It passes all tests. But is O(n log n)....

gist.github.com

string null conditional check ?. will cause duplicate null check, so it may take bit more time.

No LINQ

I like LINQ but let's try no LINQ. Looks like better performance, 181ms.

gist.github.com

O(n) : Dictionary

Let's remove sort and just count with Dictionary. This bring much better performance, only 124ms.

gist.github.com

Also here's my friend @ichiohta's code.

gist.github.com

It takes much time in .GroupBy().ToDictionary(). Swap with my code brings 267ms -> 127ms.

gist.github.com

Dictionary is much better performance than Sort algorithm.

Conclusion

Pattern Algorithm time in 12 test x 100000
Sort (LINQ : Enumerable.SequenceEqual) O(n log n) 280ms
Sort (LINQ : Enumerable.SequenceEqual + ?.) O(n log n) 290ms - 580ms
Sort (NO LINQ) O(n log n) 181ms
Dictionary (NO LINQ) O(n) 124ms
Dictionary (LINQ : GroupBy().ToDictionary()) O(n) 267ms

What's the most readable and fast enough code for you? More idea is much appreciated.

Azure Functions で SSLサーバー証明書の有効期限を監視する

久しぶりの AzureFunctions 記事です。この間、グラニでは更に Functions が増えてずいぶんと楽になりました。Function as a Service (FaaS) だけでも非常に助かるものです。もちろん Lambda のような Backend as a Service (BaaS) にはまだまだ足りませんが、それでも素晴らしいサービスです。

さて、最近 Lambda ではあるのに Azure Functions では書いてなかったので、C# でSSLサーバー証明書の有効期限をチェックするものを公開します。

目次

SSL サーバー証明書の確認

SSL サーバー証明書は、独自ドメインで HTTPS なサイトを建てる時などに付きまとうめんどくさい筆頭の1つです。何しろめったにないので殊更に厄介です。個人的に、DV証明書もEV SSL証明書もどうでもいいのですが企業では選択せざるを得ないこともあるでしょう。

グラニでは全面的に Amazon Certificate Manager を活用しており、基本的に AWS における証明書問題は生じません。AWS素晴らしいです。使てない方はぜひ検討してください。

しかし、Azure WebSites が問題です。Azure には ACMに相当する機能もないので、仕方なく証明書をあげたりすることになります。メンドクサイ。

監視ソフトウェアやエクセルで確認とか無理ですし、OpenSSL もなしでしょう。C# で一発で行きましょう。

サイト証明書の有効期限を確認

肝心のサイトの証明書状態の確認は非常にシンプルです。

gist.github.com

TimerTrigger による定期実行

TimerTrigger を使えば、外部からのイベントやリクエストなしにFunctions を実行できます。function.json をファンクション名のフォルダ直下に作成します。

gist.github.com

日付は、cron 書式で UTC にて指定します。もし Local Time Zone で指定したい場合は、App Settings で WEBSITE_TIME_ZONE を指定しましょう。

後は先ほどのコードをAzure Functions に組み込んだ run.csx を置くだけです。今回もAzureFunctionsIntroduction リポジトリにコードを追加しておきました。

github.com

実行テスト

Azure Portal で実行してみましょう。

うまく動いていますね。

2016-09-12T19:15:57  Welcome, you are now connected to log-streaming service.
2016-09-12T19:16:02.593 Function started (Id=c2036a4f-848c-4209-aa35-be555d917655)
2016-09-12T19:16:02.593 SSLCertificateExpireCheck timer triggered!
2016-09-12T19:16:02.812 There are no limit SSLs. SSLCertificateChecker finished without sending notification. Message :
2016-09-12T19:16:02.812 Function completed (Success, Id=c2036a4f-848c-4209-aa35-be555d917655)

期限を 30日にしていますが、100日など伸ばすことでどうなるかを見ることもできます。

Timer 設定も問題ありません。ここ1か月で 設定画面に設定したTriggerごとの説明が追加されてわかりやすくなりました。

ちなみに Development 画面で、ファンクションのフォルダ内部を見たり直接アップロードも可能になりました。

AzureFunctions へのフィードバック

使っていれば苦しい部分も出てきます。幸いにも Azure Functionsチームは、私が過去に出会ったチームの中でも非常にアグレッシブでポジティブなチームです。つまり、フィードバックを投げれば何かしらの反応と改善が期待できます。

現在、使っていて誰もがである苦しさに関して 2つIssue を挙げています。RunTimeのどこで改善が入るかわかりませんが、楽しみに待っていましょう。

これは、Continuous Delivery をしているとException が発生しても詳細がわからないことのフィードバックです。CD回りはいくつか他にもありますが、チームの温度間として結構クリティカルに感じているようなのでまとめて修正されそうです。

https://github.com/projectkudu/AzureFunctionsPortal/issues/439github.com

これは先日のUI変更で、App Service Editor (以前の Visual Studio Online) のアクセスがほしいというものです。もちろん結局のところはUI変更に至るでしょうが、Azure Portal の最大の短所である遷移の遅さは苦しいので楽したいですね。

https://github.com/projectkudu/AzureFunctionsPortal/issues/535github.com

まとめ

SSL 証明書をはじめとしてドメインの期限など定期的に、でもめったにないもの。というのはまさにFaaS の出番です。動的にも確認でき、最も好ましい方法として定着すると嬉しいですね。

Runtime 0.5 から F# も第一級サポートになったのでなんか適当に書いてみましょうかね。

https://mnie.github.io/2016-09-08-AzureFunctions/?utm_content=buffer431a1&utm_medium=social&utm_source=twitter.com&utm_campaign=buffer

はてなブログPro の更新が失敗したお話

はてなブログはかれこれ 3年になるのですが、毎度更新がひやひやです。他にも同じように感じていらっしゃる方もちらほら見かけます。

はてなブログProの契約を更新した - なか日記

さて、今回もいつも通り はてなポイントを用意して待っていたら

なるほど、何か間違えたかなぁということで見ていきましょう。この記事を書いている時点で切れた状態です。

目次

状態

さて、メールではてなブログPro 停止と来ましたが、管理ページの状態は次の通りです。

メールの停止通知と違い、Pro の機能がまだ残っています。Pro停止と 機能停止は別処理のようですね。おいおい停止されるのでしょう。

はてなブログProの更新は、「更新時に更新分のはてなポイント があれば自動更新」だったと記憶していたのですが、更新条件を間違えたか確認します。

ご利用料金は、はてなポイントでお支払いいただきます。コースごとの利用期間分の先払いとなり、ご利用開始時および自動更新時に、必要なはてなポイントの引き落としが発生します。引き落とし時点ではてなポイントの残額が不足している場合、はてなブログProの機能は利用停止(解約扱い)となります。

あってそうですが....ポイントは 1年分で 8434 ポイントを購入しておいたのですが、間違えたでしょうか?

登録ページから行くと、引かれてませんね。

更新というか再開?

埒が明かないので、はてなブログPro に再度申し込みましょう。

できましたね... なんなんでしょうか。

いい機会なのでツイートもしておきましょう。

確認メールも届きましたが、私の理解がおかしいんでしょうかねぇ..。

まとめ

blog.nakajix.jp

にある通り、事前に はてなポイントを購入しているのだからその時点で更新の意思があるし、先に更新を確定させてくれれば済む話だと思うのですが.... 原因がわかればいいのですが、わからないなら来年は別ブログに行くかもしれませんね。シカタナイ。