tech.guitarrapc.cóm

Technical updates

AzureFunctions の Precompiled Functions を試してみる

2017/1/6 に Precompiled Functions がサポートされました!! この対応により、C# Scripting (.csx) に比べてかなり Azure Functions が書きやすくなります。早速Precompiled の利用とこれまでの.csxとの違いを見てみましょう。

buchizo.wordpress.com

目次

Precompiled Function の概要

「ビルド済みのdll」 と 「dllを使うことを明示した function.json」 を設置することで、.csx で発生していたコンパイルがスキップされ指定したメソッドをエントリポイントとして関数が実行されます。

2017/1/13 現在、.NET Framework v4.6 (Full Desktop) がdllの対象となります。このバージョンは Azure App Service の制限となるので、将来の.NET Framework 対応はそれ待ちです。

なお、.NET Core 対応 はされていません。すでに Issue に上がっていますが、Microsoft.Azure .WebJobs をはじめとする ライブラリやAPIの解決が待たれる状態です。これができると、AWS Lambda とのマルチクラウドにおけるコード運用も可能になるので、かなりいいのですが..。

github.com

github.com

実際、最新の 1.1.2 を試してみても、ね?

さて、改めてPrecompiled Functions を使う理由ってなんでしょうか? 個人的には、.csx で解消できなかった IDE 支援の下でのC#の記述、dllコンパイルによる挙動のわかりやすさ、ローカル環境での動作検証の容易さがその使う理由です。

Pros

ザクッとあげます。要は普通にC# が Visual Studio などのIDE支援で書けるのって嬉しいですね、デプロイ不要でローカルデバッグできるのいいですね。ということです。

メリット一覧 内容
IDE のフル支援が受けられる Visual Studio や VS Code をはじめとする任意のIDEでいつも通りC#を書けます。.csx では、インテリセンスをはじめとしたIDE支援が制限された中で書くことが強いられていたため、普通にかけるのは嬉しいものです。
ローカル動作の確認 dllにコンパイル済みなので、些細なミスによるコンパイル失敗は完全に避けられます。些細なのですが、; 忘れだったり結構IDEに頼っていることを自覚させられる生活から解放されます。*1
一定の動作保証 ローカルで動作確認した上でCI/CDするため、おおよそ意図通り動くことが期待できます。*2
Cons

WebUI での編集ができない。の一言です。AWS Lambda における Java や C# (.NET Core) と同じです。

実際、Precompiled Functions は WebUI 上でみてもコードは表示されず文字化け状態で表示されます。*3

Precompiled Functions を作成してみる

ミニマムコードサンプルはWikiにあります。

github.com

今回は、ミニマムコードにない Logger を含めてやってみましょう。コードはいつも通り、Github に挙げておきました。PrecompileFunctions.sln にソースをいれてあります。

github.com

コード全体像は次の通りです。

gist.github.com

このプロジェクトをビルドすればルート直下にPreCompileEnvironmentVariables フォルダを作成して、ビルド済みdll、function.json が一緒に配置されます。ちなみに、nuget パッケージを一切追加しない状態だと次のようなエラーが出ます。そこで、必要なパッケージを追加して解決しています。

テストすると、上手く動きましたね?

エントリポイントのメソッドを含めるクラスの注意

dll を配置した場合のエントリポイントは、function.json に記述した次の2文で指定します。

  "scriptFile": "PreCompileEnvironmentVariables.dll",
  "entryPoint": "PreCompileEnvironmentVariables.MyFunction.Run",
キー 設定する内容
scriptFile コンパイルしたエントリポイントとなるdll を指定します。
entryPoint NameSpace.Class.Methodの形式でエントリポイントを指定します。

例では、MyFunctionクラスのRunメソッドをエントリポイントに指定しています。このRunメソッドを含む MyFunctionクラスには、Runメソッド以外を含めるとエントリポイントを見つけられないようです。つまり、インスタンスフィールドなどは書かず、Runメソッドだけ書いてください。

ロガーについて

ロガーを利用するには Microsoft.Azure.WebJobs nugetパッケージの追加をしましょう。ミニマムコードのRunメソッドシグネチャに TraceWriter がありませんが、実は渡ってきています。このnugetパッケージがあれば、.csx 同様にTraceWriter を実装せずともロガーとして利用できます。

これにより、エントリポイントのメソッドシグネチャはpublic static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)のように書けます。これでこれまで通り、log.Info("なにかログ") とするだけでロギングできて便利!

HttpRequestMessage の拡張メソッドについて

.csx と同じように HttpRequestMessage の拡張メソッドを利用するため、Microsoft.AspNet.WebApi.Core nuget パッケージの追加をしましょう。これにより、HttpResponseMessage CreateResponse<T>(this HttpRequestMessage request, HttpStatusCode statusCode, T value) などが利用可能になります。

Precompiled Functions をデプロイする

いよいよ Precompiled Functions をデプロイしましょう。Github による CD でやってみます。

従来の deployment.cmd に msbuild のセクションを追加しました。diffはこの通りです。

gist.github.com

上手くデプロイされるとFunctions がビルド後に展開され、WebUI からも見えるはずです。

ただし、w3wp.exe による dll ロック問題があるので、2度目以降のデプロイ時には Kudu コンソールで w3wp.exe をkill、WebUIでのRestart をしてあげてください。

この問題はすでに報告済みなので、解決を待ちましょう。*4

github.com

Precompiled Functions の課題

いくつか使いにくいポイントが残っています。

ビルド

今回、.slnの配置、ビルド生成物の配置をいじっていますが、CI -> CD の連携に工夫がいるのはちょっとまだ使いにくいかと思います。もう少しいい感じでデプロイできるといいのですが...。

DLLロック

現状では、Web Apps の API経由、Kudu API 経由などで w3wp やサイトのリスタートが必要です。結構ヤなポイントなので、これは解消しないと使いにくいです。コンテナベースになれば手っ取り早いのですが...。

.NET Core 対応

いずれするでしょう。待ちです。

まとめ

かなりいい感じで利用できると思います。dll の文字化けが表示されるのは愛嬌ということで。

が、dllロックは結構厄介なので、これが解消するのを待って本番に入れたいところです。AWS Lambda が主軸なのですが、サブとして Azure Functions は優秀なので、.NET Core 対応も待ち望ましいですね。

*1:その自覚別にうれしくないです

*2:環境依存の原因で動かないことはあり得るのでそこはしょうがない

*3:まるでdll をエディタで開いた時のような画面ですね

*4:Kudu Deployment Script でやるかと思いましたが、まぁ待機で。