読者です 読者をやめる 読者になる 読者になる

しばやん雑記

ASP.NET とメイドさんが大好きなフリーランスのプログラマーのブログ

Azure WebJobs の開発と運用時に便利な情報をまとめた

Azure WebJobs を利用した開発を行うことが増えてきたので、開発と運用時に便利そうな情報をまとめておくことにします。今回は WebJobs SDK についてはまとめて扱うことにします。

今回扱っている内容は以下の通りです。Kudu 側に少し偏っているかもしれません。

目次記法を初めて使ってみました。長い記事を書いた時には便利な感じです。

トリガー実行

任意のタイミングで WebJob を実行するための API が Kudu に用意されています。

https://{sitename}.scm.azurewebsites.net/api/triggeredwebjobs/{jobname}/run

SCM 側はブラウザでアクセスした場合にはフェデレーション認証が行われますが、発行プロファイルに含まれているデプロイ用のユーザー名とパスワードを使った Basic 認証も使えるようになっています。

ただし、最初から Authentication ヘッダーを送信しておく必要があるので、注意が必要です。

引数付きでトリガー実行

トリガー実行するための API を arguments というパラメータを付けて呼び出すと、それが WebJob に環境変数を経由して渡されるようになっています。

https://{sitename}.scm.azurewebsites.net/api/triggeredwebjobs/{jobname}/run?arguments={arguments}

パラメータの内容は WEBJOBS_COMMAND_ARGUMENTS 環境変数に格納されています。C# のコンソールアプリケーションとして書くと、以下のような感じです。

public class Program
{
    public static void Main(string[] args)
    {
        // args ではない
        var arguments = Environment.GetEnvironmentVariable("WEBJOBS_COMMAND_ARGUMENTS")
    }
}

引数を上手く使うことで、1 つの WebJob で挙動を変えることが出来ます。例えばバッチファイルで環境変数を処理して、実行ファイルをさらに呼び出すということも出来そうです。

:: コマンドライン引数に変換する
samplewebjob.exe -a %WEBJOBS_COMMAND_ARGUMENTS%

パラメータの検証はしていませんが、基本的に認証済みなので問題ないはずです。

スケジュール実行

WebJob のスケジュール実行は Azure Scheduler でジョブを作成するか、ホスティングプランが標準以上であれば Internal WebJob Scheduler を使うことで実現します。

Visual Studio からのデプロイでは Azure Scheduler を、ソース管理からのデプロイでは Internal WebJob Scheduler を使うのをお勧めします。前者はポータルか PowerShell などで別途設定が必要ですが、後者は設定ファイルのみでスケジュール実行可能です。

トリガー実行後の Webhook

トリガー実行の WebJob が完了したタイミングで Webhook の実行が可能です。Kudu に設定画面が用意されているので、ここから Webhook を追加していきます。

f:id:shiba-yan:20150909231435p:plain

Webhook の実行時にペイロードとして渡される JSON は以下のような形式になっています。

{
    "id": "201509151257372805",
    "name": "201509151257372805",
    "status": "Success",
    "start_time": "2015-09-15T12:57:37.2805391Z",
    "end_time": "2015-09-15T12:57:37.6332727Z",
    "duration": "00:00:00.3527336",
    "output_url": "https://azure-deploy-posh.scm.azurewebsites.net/vfs/data/jobs/triggered/triggerjob/201509151257372805/output_log.txt",
    "url": "https://azure-deploy-posh.scm.azurewebsites.net/api/triggeredwebjobs/triggerjob/history/201509151257372805",
    "job_name": "triggerjob",
    "trigger": "External - Portal-Exp/5.12.0.126 (Websites) Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML%2C like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240"
}

これはポータルから実行した例になります。Webhook の先を Hubot や Slack に設定すれば楽しめそうです。

Visual Studio からのデプロイ

コンソールアプリケーションの場合、ソリューションエクスプローラの右クリックメニューに「Azure WebJob として発行する」メニューが表示されるので、これを使うだけで簡単にデプロイできます。

f:id:shiba-yan:20150915222335p:plain

選択すると WebJob としての基本的な設定を行うダイアログが表示されます。

f:id:shiba-yan:20150915222252p:plain

実行モードからスケジュール実行を選ぶと自動的に Azure Scheduler が作成されるので、その点だけは注意が必要です。個人的には Internal WebJob Scheduler を使うのがおすすめです。

ソース管理からのデプロイ

GitHub などのソース管理を使って WebJob のデプロイを行うには、出力先の App_Data ディレクトリ以下に決められたフォーマットでファイルを配置するだけになります。

カスタムデプロイスクリプトを使って方法はすでに紹介しているので、こちらを参照してください。

Web App へのデプロイ時の注意

WebJobs は wwwroot 以下の App_Data 内に保存されることになっているので、デプロイ時に既存ファイルを削除するような設定にしていると、稼働中の WebJobs 含め、全て削除されるので注意が必要です。

f:id:shiba-yan:20150915221550p:plain

デプロイ設定にある「発行前に既存のファイルをすべて削除する」のチェックが入っていると削除されます。

ただし Visual Studio から WebJobs へのリンクを追加していると、同時にデプロイされるので問題になりませんが、別々のプロジェクトで作成している場合には注意が必要です。

HTTP リクエストのパススルー

最新の Kudu で連続実行する WebJob に対して、TCP のポートが用意されるようになりました。

ポートの開放を TcpListener を使っているので、http.sys を使っているサーバーは使えませんが、ソケットで実装されている HTTP サーバーは使えます。手軽に試したいので Go を使いました。

package main

import (
  "fmt"
  "net/http"
  "os"
  "runtime"
)

func viewHandler(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "Hello, World, " + runtime.Version())
}

func main() {
  http.HandleFunc("/", viewHandler)
  http.ListenAndServe(":" + os.Getenv("WEBJOBS_PORT"), nil)
}

いつも通りなコードを server.go という名前で保存します。HTTP_PLATFORM_PORT 環境変数でポート番号を取っていた部分を WEBJOBS_PORT に変更するだけです。

実行用のバッチファイルとして、以下のような内容で run.cmd を作成しておきます。WebJobs では run.* という名前のファイルが優先して実行されるようになっています。

SET GOROOT=D:\Program Files\go\1.5

"%GOROOT%\bin\go.exe" run server.go

HTTP リクエストのパススルー用のエンドポイントは以下の URL になります。サイト名と WebJob 名を入れて、ブラウザから呼び出せば実行の確認ができます。

Basic 認証のヘッダーを付けて叩けば、任意のアプリから呼び出し可能です。

https://{sitename}.scm.azurewebsites.net/api/continuouswebjobs/{jobname}/passthrough/{path}

実際にブラウザから上の URL を叩くと、Go で書いたコードが実行されていることが分かります。

f:id:shiba-yan:20150912161350p:plain

WebJob 間の通信として HTTP が使えるので、リアルタイムな処理が作りやすくなった感があります。

ログ出力の方法

WebJob の実行時ログは Kudu が標準出力を監視してくれているので、Console.WriteLine などで書き出すだけで行えるようになっています。

そのままだと日本語を書き出すと文字化けするので、出力エンコードの設定を行う必要があります。

WebJobs SDK を使っている場合には TextWriter をバインドしてログ出力を行います。

複数の実行ファイルがある場合の指定

外部の実行ファイルを含んだ WebJob を作成した場合、エントリポイントが WebJob からは認識できなくなるため、一般的には run.cmd という名前でバッチファイルを作成しておきます。

ちなみに Kudu が実行ファイルを選択する基準は以下のような感じです。

  1. run.{ext} というファイル名を探す
  2. *.{ext} というファイル名を探す

拡張子は cmd / bat / exe / ps1 / sh / php / py / js の順に検索されます。なので run.cmd を用意しておけば、他に実行ファイルが複数あったとしても必ず実行の対象となるわけです。

設定ファイルについて

WebJob の設定は settings.job というファイルを用意して行います。

  • is_singleton : シングルトン実行を行うかどうか
  • stopping_wait_time : Kudu によって WebJob が強制終了を行うまでの待ち時間
    • Graceful Shutdown と関係
  • is_in_place : WebJob を Temp に移動させずに直接実行するかどうか
    • 実行中にファイルがロックされて、デプロイに問題が出る場合があるので注意
  • schedule : Internal WebJob Scheduler を利用した実行スケジュール
    • crontab 形式でスケジュールを指定

設定ファイルの例は以下のような感じになるので、WebJob のルートに保存しておきます。

{
  "is_singleton": false
  "stopping_wait_time": 180,
  "is_in_place": false,
  "schedule": "0 0 * * * *"
}

これで Kudu が認識して、スケジュール実行なりシングルトンといった処理を行ってくれます。

WebJob のスケールアウト

全ての WebJob はホスティングプランに連動してインスタンスが増えるので、Web Apps と同様に数秒でスケールアウトが可能です。スケールアップも同様です。

Azure WebJobs 105 - Scaling out Web Jobs | Azure Friday | Channel 9

Channel 9 で公開されている Azure Friday で扱われているので、こちらも参照してください。

シングルトンとして実行

実行する WebJob によっては、スケールアウトさせたくない、全体 1 つだけ実行させておきたい WebJob も存在すると思います。その場合にはシングルトンとして実行させるオプションを設定します。

f:id:shiba-yan:20150909231635p:plain

ポータル以外から設定する場合には、WebJob に設定ファイルを置いて行います。

How to Run a Continuous WebJob as a Singleton - Microsoft Azure App Service Web Apps Support Team Blog - Site Home - MSDN Blogs

シングルトンとしての実行は重要な機能ですね。

Graceful Shutdown の実装

WebJob では Graceful Shutdown が標準でサポートされています。特定のファイルを監視して、変更があった場合にはシャットダウンを行うという実装方法になります。少し長いのでドキュメントを紹介しておきます。

WebJobs Graceful Shutdown - Blog.Amit Apple

How to use Azure queue storage with the WebJobs SDK

ちなみに Azure WebJobs SDK を使うと CancellationToken で簡単に実装できます。

Azure WebJobs SDK を使う

既に何回か扱っているため、該当する記事の紹介にとどめておきます。

公式ドキュメント

Azure WebJobs のドキュメントは GitHub や公式サイトに数多く用意されています。

Web jobs · projectkudu/kudu Wiki · GitHub
WebJobs API · projectkudu/kudu Wiki · GitHub
Azure WebJobs documentation resources

特に Azure 公式サイトのドキュメントが充実しています。WebJob は更に活用していきたい機能です。