前回からの続きです。
前回は『ClientとServerの双方を同一のASP.NET Webアプリケーションに実装』しましたが、今回はこれを分離してみたいと思います。
Hangfire Clientと Hangfire Serverを別プロセスにする
今回は『ClientはASP.NET Webアプリケーション、ServerをWindowsコンソールアプリケーションで実装』を試してみます。またClientとServerを別にするだけでなく、ジョブとして実行する処理もDLLとして切り出しておくことにします。
ソリューションは前回使ったものに手を入れていきます。
実装手順
1. ジョブのDLLを作成
ソリューションにWindowsクラスライブラリのプロジェクト『MyJobsLib』を追加して、ジョブとして実行したい処理のクラスを実装します。ジョブはCustomJob.csとして、実行結果が分かり易いようにTempフォルダにテキストファイルを吐き出すような処理にしてみました。
// CustomJob.cs using System.IO; namespace MyJobsLib { public class CustomJob { public void Execute(string message) { var fileName = string.Format("HangfireJob_{0}.txt", System.Guid.NewGuid()); var filepath = Path.Combine(Path.GetTempPath(), fileName); using (var writer = new StreamWriter(filepath, true)) { writer.WriteLine(message); } } } }
2. Webアプリケーションの書き換え
Webアプリケーション側は主に以下の2点対応を行います。
- キューに登録するジョブを習性
- OWIN StartUpからHangfire Serverの登録を削除
まず、[参照の追加]等からMyJobsLibを参照したうえで、BackgroundJob.Enqueue
で登録するジョブをDLL内のものに変更します。
// HomeController.cs using Hangfire; using System.Web.Mvc; namespace HangfireSample01.Web.Controllers { public class HomeController : Controller { public ActionResult Index() { // Hangfireでjobをキューに登録 BackgroundJob.Enqueue(() => new MyJobsLib.CustomJob().Execute("Job Executed.")); // ★ここを変更 return View(); } public ActionResult About() { ViewBag.Message = "Your application description page."; return View(); } public ActionResult Contact() { ViewBag.Message = "Your contact page."; return View(); } } }
次に、Statup.csでHangfire Serverの登録を行っていた箇所を削除します。
// Startup.cs using Hangfire; using Microsoft.Owin; using Owin; [assembly: OwinStartup(typeof(HangfireSample01.Web.Startup))] namespace HangfireSample01.Web { 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(); ★ここを削除 } } }
3. コンソールアプリケーションの作成
最後に、Hangfire Serverとして動作させるコンソールアプリケーションを作成します。ここはオフィシャルのドキュメントProcessing jobs in a console applicationを参考に……というかほぼそのままです。
コンソールアプリケーションプロジェクト追加
ソリューションに『HangfireSample01.ServerConsole』という名前でコンソールアプリケーションプロジェクトを追加しました。
ジョブのDLLを参照する
[参照の追加]等からMyJobsLibの参照を追加します。ちなみにこの追加を行わなくてもビルドでエラーが出ないので、うっかり忘れると実行時に例外に遭遇することになります(経験者談)。
NuGetパッケージをインストール
サーバーとして動作させるだけの場合、必要なパッケージは限られるます。オフィシャルにドキュメントに従い、Hangfire.Core
とHangfire.SqlServer
のみをインストールしました。パッケージマネージャーコンソールから行う場合は以下の操作になります。
PM> Install-Package Hangfire.Core
PM> Install-Package Hangfire.SqlServer
Hangfire Serverの起動処理を実装
最後にProgram.csにHangfire Serverの起動処理を書きます。UseSqlServerStorage
メソッドの引数に渡す接続文字列は、Webアプリケーション側で指定したのと同じものを指定します。それ以外はオフィシャルのドキュメントのそのままです。
// Program.cs using Hangfire; using System; namespace HangfireSample01.ServerConsole { class Program { static void Main(string[] args) { var constr = @"Data Source=localhost;Initial Catalog=HangfireJob;Integrated Security=True"; GlobalConfiguration.Configuration.UseSqlServerStorage(constr); using (var server = new BackgroundJobServer()) { Console.WriteLine("Hangfire Server started. Press any key to exit..."); Console.ReadKey(); } } } }
実行して確認する
以上で準備が完了したので早速実行してみます。
……と言いつつ、簡単に実行するために実行前にもう一つ設定しておきます。ソリューションの[スタートアッププロジェクトの設定]で、コンソールアプリケーションとWebアプリケーションの両方を実行するように設定しておきます。
この状態でF5でデバッグ実行を開始するとブラウザとコンソールアプリケーションの両方が起動すると思います。起動したらHangfireのダッシュボードを表示し、jobの状態を確認してみると、ちゃんとジョブが実行されていることが確認できました。
また、Tempフォルダにファイルが作成されていることも確認できました。
ここまでのまとめ
ClientとServerの分離を試してみました。今回はConsoleアプリケーションでやりましたが、他の形態でも基本は変わらないように思います。またオフィシャルのドキュメント Processing jobs in a Windows Service にはWindowsサービスでの実装について書かれています。
今回のソースは以下のリポジトリのstep02ブランチになります。
次回は、DIコンテナを用いてさらに実用的な構成の検証をしていきます。