Hangfire は、.NET アプリケーション向けの分散型ジョブスケジューラであり、データベース(MySQL や SQL Server など)を用いてジョブ状態を永続化できます。本稿では、ASP.NET Core 7/8 環境下で MySQL をストレージとして Hangfire を構成・運用する方法を、実践的な設定とコード例を交えて解説します。
必要な NuGet パッケージ
Hangfire.AspNetCoreHangfire.MySqlStorage
サービス登録とミドルウェア設定
以下は、Program.cs における最小限かつ堅牢な設定例です。接続文字列は構成ファイル(例:appsettings.json)から読み込み、MySQL ストレージの各種オプションを明示的に指定しています。
using Hangfire;
using Hangfire.MySql;
using Microsoft.Extensions.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
// Hangfire のストレージ設定(MySQL 使用)
var hangfireConnectionString = builder.Configuration.GetConnectionString("HangfireDb")
?? throw new InvalidOperationException("HangfireDb connection string is missing.");
builder.Services.AddHangfire(config => config
.UseStorage(new MySqlStorage(hangfireConnectionString, new MySqlStorageOptions
{
TransactionIsolationLevel = System.Transactions.IsolationLevel.ReadCommitted,
QueuePollInterval = TimeSpan.FromSeconds(10),
JobExpirationCheckInterval = TimeSpan.FromHours(2),
CountersAggregateInterval = TimeSpan.FromMinutes(3),
PrepareSchemaIfNecessary = true,
DashboardJobListLimit = 10000,
TransactionTimeout = TimeSpan.FromMinutes(2),
TablesPrefix = "hf_"
})));
// Hangfire サーバー(ジョブ実行エンジン)を登録
builder.Services.AddHangfireServer(options =>
{
options.WorkerCount = Environment.ProcessorCount * 5;
options.Queues = new[] { "default", "critical" };
});
// 定期ジョブ登録用のホステッドサービスを追加
builder.Services.AddHostedService<ScheduledJobRegistrar>();
// その他のサービス(Controllers, Swagger など)
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Hangfire ダッシュボードを有効化(デフォルトパス: /hangfire)
app.UseHangfireDashboard("/hangfire", new DashboardOptions
{
Authorization = new[] { new CustomDashboardAuthorizationFilter() }
});
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
定期ジョブの自動登録(ホステッドサービス)
アプリケーション起動時に Cron 式に基づきジョブを登録するため、カスタム BackgroundService を実装します。以下のクラスでは、複数のタイムゾーンや間隔を持つジョブを一括登録し、エラー発生時もプロセスが停止しないよう例外処理を組み込んでいます。
using Hangfire;
using Hangfire.Server;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace Infrastructure.Jobs;
public class ScheduledJobRegistrar : BackgroundService
{
private readonly IRecurringJobManager _jobManager;
private readonly ILogger<ScheduledJobRegistrar> _log;
public ScheduledJobRegistrar(IRecurringJobManager jobManager, ILogger<ScheduledJobRegistrar> log)
{
_jobManager = jobManager;
_log = log;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
{
// 毎15秒(UTC)
_jobManager.AddOrUpdate(
"heartbeat-utc",
() => Console.WriteLine($"[UTC] Heartbeat at {DateTime.UtcNow:o}"),
"*/15 * * * * ?",
new RecurringJobOptions { TimeZone = TimeZoneInfo.Utc });
// 毎分(ローカルタイムゾーン)
_jobManager.AddOrUpdate(
"daily-report",
() => Console.WriteLine($"[Local] Report generated at {DateTime.Now:o}"),
Cron.Minutely,
new RecurringJobOptions { TimeZone = TimeZoneInfo.Local });
// 毎日午前2時(日本標準時)
var jst = TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time");
_jobManager.AddOrUpdate(
"cleanup-jst",
() => Console.WriteLine("Running daily cleanup in JST..."),
"0 0 2 * * ?",
new RecurringJobOptions { TimeZone = jst });
// 毎時15分(米国ハワイ時間)
var hst = TimeZoneInfo.FindSystemTimeZoneById("Hawaiian Standard Time");
_jobManager.AddOrUpdate(
"hawaii-alert",
() => Console.WriteLine("Hawaiian time alert fired."),
"0 15 * * * ?",
new RecurringJobOptions { TimeZone = hst });
_log.LogInformation("All recurring jobs registered successfully.");
}
catch (Exception ex)
{
_log.LogError(ex, "Failed to register recurring jobs.");
}
// 一度だけ実行 → 終了
await Task.CompletedTask;
}
}
ダッシュボードとデータベース構造
アプリケーション起動後、https://localhost:5001/hangfire(または任意のホスト/ポート)にアクセスすると、Hangfire の管理ダッシュボードが表示されます。MySQL には、hf_ 接頭辞付きの以下のテーブル群が自動生成されます:
hf_job(ジョブ定義)hf_state(ジョブ状態履歴)hf_jobparameter(パラメータ)hf_jobqueue(キュー)hf_hash,hf_list,hf_set,hf_counter(内部カウンター・集合)
これらのテーブルにより、ジョブの再試行、監査、失敗分析が可能になります。