2017/1/6 に Precompiled Functions がサポートされました!! この対応により、C# Scripting (.csx) に比べてかなり Azure Functions が書きやすくなります。早速Precompiled の利用とこれまでの.csxとの違いを見てみましょう。
Nice. Precompiled functions in Azure Functions https://t.co/fZPFSTl8D3
— Jeremy Hutchinson (@hutchcodes) 2017年1月5日
目次
- 目次
- Precompiled Function の概要
- Precompiled Functions を作成してみる
- Precompiled Functions をデプロイする
- Precompiled Functions の課題
- まとめ
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 とのマルチクラウドにおけるコード運用も可能になるので、かなりいいのですが..。
実際、最新の 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にあります。
今回は、ミニマムコードにない Logger を含めてやってみましょう。コードはいつも通り、Github に挙げておきました。PrecompileFunctions.sln
にソースをいれてあります。
コード全体像は次の通りです。
このプロジェクトをビルドすればルート直下に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
メソッドだけ書いてください。
@guitarrapc_tech あー、多分 log をRun()内で宣言すると行けると思います。どうもRun()以外は本当に何も置いちゃいけないっぽいです
— 帝国兵 (@superriver) January 10, 2017
ロガーについて
ロガーを利用するには 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はこの通りです。
上手くデプロイされるとFunctions がビルド後に展開され、WebUI からも見えるはずです。
ただし、w3wp.exe による dll ロック問題があるので、2度目以降のデプロイ時には Kudu コンソールで w3wp.exe をkill、WebUIでのRestart をしてあげてください。
@guitarrapc_tech あとDLLがロックされてるので、置き換えるときは一度FunctionをStopしてw3wpをkillしてからの方が確実のようです。
— 帝国兵 (@superriver) January 10, 2017
この問題はすでに報告済みなので、解決を待ちましょう。*4
Precompiled Functions の課題
いくつか使いにくいポイントが残っています。
ビルド
今回、.slnの配置、ビルド生成物の配置をいじっていますが、CI -> CD の連携に工夫がいるのはちょっとまだ使いにくいかと思います。もう少しいい感じでデプロイできるといいのですが...。
DLLロック
現状では、Web Apps の API経由、Kudu API 経由などで w3wp やサイトのリスタートが必要です。結構ヤなポイントなので、これは解消しないと使いにくいです。コンテナベースになれば手っ取り早いのですが...。
.NET Core 対応
いずれするでしょう。待ちです。
まとめ
かなりいい感じで利用できると思います。dll の文字化けが表示されるのは愛嬌ということで。
が、dllロックは結構厄介なので、これが解消するのを待って本番に入れたいところです。AWS Lambda が主軸なのですが、サブとして Azure Functions は優秀なので、.NET Core 対応も待ち望ましいですね。