最近 Hangfire について調査・検証しているのでメモ。
Hangfireとは
Hangfireは.NET向けのバックグランド・タスクのライブラリです。
ストーレージにタスクをキューイングして、非同期に実行させることができます。即時実行だけでなく、cronっぽい感じで定期実行したりもできる模様。 OWIN Middleware としてASP.NETで利用できるほか、コンソール/WPF/Windows Form/Windows サービス等など……でも使えます。
今回から予定している一連のエントリは『ASP.NETのWebアプリケーションから重たい処理(例:集計帳票作成処理)を非同期実行させる』という観点での調査検証に基づいています。ですので、ある程度方より(?)がある点はご了承ください。
Hangfireを構成するコンポーネント
Hangfireはざっくりと以下のようなコンポーネントで構成されています。
コンポーネント | 役割 | 典型的な実装 |
---|---|---|
Hangfire Client | Jobをキューへ登録 | ASP.NET等, ユーザーが操作するアプリ |
Job Storage | Jobのキュー,その他管理情報を格納 | SQL Server / Redis 等 |
Hangfire Server | キュー上のJobの実行 | ASP.NET(バックグラウンド) / Windowsサービス等 |
Hangfire ClientとHangfire Serverは同一のプロセス上で実装可能です*1。 そのほか、ASP.NET用にビルトインされていてるダッシュボード機能があり、jobの状況のモニタリングや再実行などの操作を行うことができます。
とりあえず試してみる
チュートリアル的に一番シンプルで試しやすい構成として、『ClientとServerの双方を同一のASP.NET Webアプリケーションに実装』するパターンを試してみます。
https://github.com/kiyokura/HangfireSample01/tree/step01
基本構成
とりあえずこんな感じでやってみました。
- Visual Studio 2015
- ASP.NET MVC 5
- SQL Server 2016
実装手順
1. SQL ServerでHangfire用のDBを作成
Jobストレージとして利用するデータベースが必要なので適当に作成しておきます。データベース内にはHangfireスキーマといくつか専用のテーブルが作成されます*2。
2. ASP.NET MVCのプロジェクトを作成する
Visual Studio 2015で適当にASP.NET MVCのプロジェクトを作成しました。
3. NuGetでHangfireのパッケージを取得
NuGetでHangfireを取り込みます。コマンドラインからだとInstall-Package Hangfire
でOK。
4. OWINスタートアップを記述
Hangire の最低限必要な設定をOWINスタートアップで行うように記述します。Webアプリケーションプロジェクトの直下にOWIN Startupクラス「Startup.cs」を追加して、以下のように書きました。
using Hangfire; using Microsoft.Owin; using Owin; [assembly: OwinStartup(typeof(HangfireSample01.Startup))] namespace HangfireSample01 { public class Startup { public void Configuration(IAppBuilder app) { // 接続文字列は環境に応じて変えること var constr = @"Data Source=localhost;Initial Catalog=HangfireJob;Integrated Security=True"; GlobalConfiguration.Configuration.UseSqlServerStorage(constr); app.UseHangfireDashboard(); app.UseHangfireServer(); } } }
5. Jobの登録処理を記述
最後に実際にjobをキューに登録する処理を書きます。既存のHomeControllerのIndexアクションメソッドに、とりあえずコンソールに文字を出力するだけの単純な処理をjobとして登録するように書いてみました。
using Hangfire; using System; using System.Web.Mvc; namespace HangfireSample01.Controllers { public class HomeController : Controller { public ActionResult Index() { // Hangfireでjobをキューに登録 BackgroundJob.Enqueue(() => Console.WriteLine("Simple Job")); return View(); } public ActionResult About() { ViewBag.Message = "Your application description page."; return View(); } public ActionResult Contact() { ViewBag.Message = "Your contact page."; return View(); } } }
実行して確認する
準備が終わったので実行してみます。
1.WebアプリケーションをF5で実行
F5でデバッグ実行を開始すると見慣れた(?)ASP.NET MVCのテンプレートのホーム画面が表示されます。このとき、Home/Indexアクションメソッドが実行されているので裏ではキューにjobが登録され、そして実行されているはずです。
次の手順でそのあたりを確認してみます。
2.Hangfireダッシュボードを表示
Hangfire組み込みのダッシュボードを利用してjobの状況を確認してみます。hangfireダッシュボードは、アプリケーションルート+/hangfire
というURLでアクセスできます。今回のようにIIS Expressでローカル実行している場合は例えば以下のようになります
http://localhost:61828/hangfire
(※ポート番号は環境によって変わります)
アクセスできるとこんな感じのダッシュボードが表示されます。
3.jobの実行状況を確認
ダッシュボードで実際のjobがどのようになっているかを確認します。
メニューから[jobs]-[Succeeded]
とたどっていくと、成功したジョブ一覧に先ほど登録したjobが並んでいるのが見えました。
さらにjob名をクリックすると詳細情報が見れます。
4.データベース(Job Storage)を確認
最後に、Job Storageとなっているデータベースを簡単に確認してみました。
SSMSで該当のデータベースを開いてみると、こんな感じでテーブルが作成され、例えばHangfire.Jobテーブルにはこんな形でJobが格納されているのが分かります。
ここまでのまとめ
Hangfireのクイックスタート的な感じでとりあえず手元で基本的な動作をさせてみました。というか、オフィシャルのドキュメントのQuick Startにあるそのままです。
なお、ここまでのサンプルコードは以下にあります
このHangfire ServerもASP.NETのインプロセスで動かすモデルの場合、ASP.NETの標準仕組の HostingEnvironment.QueueBackgroundWorkItem と似ているようにも見えます。しかしキューが永続化されているためjobのトレースやリトライ等QueueBackgroundWorkItemでは実現困難なことが簡単に実現できる点や将来的なスケールアウトの容易さ等、差別化のポイントはいくつもあるように思います。 (一方QueueBackgroundWorkItemはインプロセス前提なのでHttpContext等ASP.NETの実行インスタンスに依存する情報をHangfire よりもよりシンプルに扱うことができる等のメリット?はあかなーと思ったりもします)
次はClientとServerを別プロセスでやってみたいと思います。