Azure App Service上のC#バッチからNode.jsベースのコマンドをさらっと叩く方法(おいしいnpmモジュールの淹れ方)

2015年10月21日水曜日

Azure App ServiceのAzure Web Apps(WebJobs)、なかなかいいです。
AWSのLambdaと似たいわゆるサーバレスなアプリケーションコードホスティングの仕組みですが、特性は割と違います。
  • AWS Lambdaは基本パッケージを50MBに抑えたプログラムを頻繁にデプロイ・破棄する構造
    • さもなくばプログラムの起動後にS3などから別途データを拾ってきて展開する(そしてtmp容量は512MBに制限されている)
    • 利用できるメモリ容量をプライマリとしてそれにCPUリソース量も紐付いた料金体系
  • Azure App Serviceは原則的にリソース予約版がメインで、共有リソース版(Lambdaのような動的アプリ展開版)はおまけ扱い
    • 共有リソース版でも最大1GBという比較的大きなアセンブリ群をホストして比較的低頻度デプロイをする想定
    • Lambdaのようにms単位でのコード実行とは謳わない
    • (個人的にはもっと共有リソース版のプラン種類を増やしてほしい)
実行ノードからアプリがアンロードされた状態からのデータロードと処理実行は、きちんと計測していませんがLambdaのほうが体感速いです。
このように実行モデルが異なるので直接比較はできませんが、Azure Web Serviceは小規模・リソース共有版なら1日あたり60分のCPU利用まで無料で使えます。こまごましたバッチを試作するのにうってつけです。

Azure上でC#とNode.jsのいいとこ取りをしたい

Node.jsというかnpm上には豊富なパッケージが存在します。
なかにはNuGetに同等のものがあるものも存在しますが、Node.js界隈に特有のものやNuGetを探すのが面倒なものも多くあります。
最近はAzure Web AppsのWebJobs(指定URLのキックによる逐次処理、定期バッチ処理、継続実行処理のデプロイモデルを選べる)を使ってバッチを書いているんですが、その中でnpm配布されているコマンドを使いたい場面がありました。餅は餅屋というわけで、Node.js方面でコマンド提供されているものを簡単にC#(.NET)から呼び出していいとこ取りをしようというのが今回の話です。

Azure Web AppsでのNode.jsサポート概要

そもそもAzureでNode.jsをまともに使えるのかという話から始まりますが、しっかり使えます。
Node.jsのバージョンはデフォルトで「アプリケーション設定」内にある設定(この場合は0.10.32)が使われますが、かなり多くのバージョンをサポートしています。
このあたりはAzure アプリケーションでの Node.js のバージョンの指定で詳しく書かれています。
今後もきちんと増えていく雰囲気です。
あっ、Azure Web Appsで実際にNode.jsが実行される環境はWindowsマシン上です。それがどうしても許せない人は諦めてください。

Node.jsベースのコマンドをインストールする

ここでは、JSONファイル同士のdiffをいい感じに出力してくれるjson-diffモジュールをインストールしてみます。
Azure Web Appsの提供するSCMへアクセスし、「Debug Console」を開きます*1
デバッグターミナルが表示されるので、npm install json-diffを実行します。
図1という具合で文字出力が一部化けて残念な感じになっていますがインストール処理は完了します。
図1 npmでのモジュールインストール
ここでnpmモジュールをインストールしたD:\home\node_modules以下のデータは、該当する処理を実行しているVMのローカルストレージではなくAzure Web Apps構成データとして保存されます。このため、割り当てられたVMが変わったりアプリのプランを変更した場合でも再度npm installをおこなう必要はありません。
[*1] https://(アプリ名).scm.azurewebsites.net/DebugConsole でアクセスできます。

C#コードからnode.jsベースのコマンドを呼び出す

試しに適当なJSONファイルとしてD:\home\node_modules\json-diff\package.jsonD:\home\node_modules\json-diff\node_modules\cli-color\package.jsonの差分を出力してみましょう。全く違うnpmパッケージのpackage.json同士なので、大量のdiffがあるはずです。
C#からの外部プロセス作成は通常通りSystem.Diagnostics.Processを利用します。
  var proc = new Process
  {
    StartInfo = new ProcessStartInfo
    {
      FileName = @"D:\home\node_modules\.bin\json-diff.cmd",
      Arguments = @"""D:\home\node_modules\json-diff\package.json"" ""D:\home\node_modules\json-diff\node_modules\cli-color\package.json""",
      RedirectStandardOutput = true,
      UseShellExecute = false,
      CreateNoWindow = true
    }
  };
完全なコードはこちら: https://gist.github.com/muojp/bb677aea6021e2a7cfaf
これを実行すると、
...
[10/20/2015 12:43:33 > 123c4b: INFO] -  _id: "json-diff@0.3.1"
[10/20/2015 12:43:33 > 123c4b: INFO] +  _id: "cli-color@0.1.7"
[10/20/2015 12:43:33 > 123c4b: INFO]    dist: {
[10/20/2015 12:43:33 > 123c4b: INFO] -    shasum: "6dbc3ae2d25e075a7fd71bcd9874458666fb681b"
[10/20/2015 12:43:33 > 123c4b: INFO] +    shasum: "adc3200fa471cc211b0da7f566b71e98b9d67347"
[10/20/2015 12:43:33 > 123c4b: INFO] -    tarball: "http://registry.npmjs.org/json-diff/-/json-diff-0.3.1.tgz"
[10/20/2015 12:43:33 > 123c4b: INFO] +    tarball: "http://registry.npmjs.org/cli-color/-/cli-color-0.1.7.tgz"
[10/20/2015 12:43:33 > 123c4b: INFO]    }
...
という感じでJSONファイル同士のdiffが出力されます。
正しいアプリベースディレクトリの取得方法がわからなかったのでD:\home\node_modulesを決め打ちしています。
このパスが変わることはひとまず無いはずですが、https://(アプリ名).scm.azurewebsites.net/api/vfs/ へアクセスして出力されるディレクトリ一覧からnode_modulesを探してくるのが正攻法な気もします。
正しい指定方法をご存知の方いらっしゃいましたら教えて下さい。

まとめ

Azure Web Apps上でnpmからNode.jsベースのコマンドを拾ってきてC#(.NET)から呼び出すのは結構簡単なので、手軽に使えそう。

0 件のコメント:

コメントを投稿