hf被定義為分布式后台服務,更加類似job作業的服務
做作業的插件有quartz.net,JobScheduler 等
當然,都有一些分別和適用的場景。
1.安裝
需要安裝
Hangfire.Core
Hangfire.AspNetCore
Hangfire.SqlServer
關於數據庫存儲工具,可以根據場景去選擇安裝
例如mysql 的,需要安裝 Hangfire.MySql (mysql很多第三方寫,所以使用時主要使用環境)
Redis放入 Hangfire.Redis
redis是官方作者去更新,所以這些使用可以直接看官網
2.配置
asp.net core主要是startup配置DI組件。
官網也有說,列舉一下
// Add Hangfire services. services.AddHangfire(configuration => configuration .SetDataCompatibilityLevel(CompatibilityLevel.Version_170) .UseSimpleAssemblyNameTypeSerializer() .UseRecommendedSerializerSettings() .UseSqlServerStorage(Configuration.GetConnectionString("default"), new SqlServerStorageOptions { CommandBatchMaxTimeout = TimeSpan.FromMinutes(5), SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5), QueuePollInterval = TimeSpan.Zero, UseRecommendedIsolationLevel = true, UsePageLocksOnDequeue = true, DisableGlobalLocks = true })); services.AddHangfireServer();
關鍵是這個鏈如何配,UseSqlServerStorage專門讀取hangfire會寫入哪個數據庫,如果用現在的業務數據庫,hangfire的表會寫進去的,也可以設計分開來存放,例如hangfire的DB,集中去管理。當然一般小的項目,直接跟業務數據庫,集中而獨立的架構。
Configure里面的配置
var jobOptions = new BackgroundJobServerOptions { Queues = new[] { "back", "front", "default" },//隊列名稱,只能為小寫 WorkerCount = Environment.ProcessorCount * 5, //並發任務數 ServerName = "conference hangfire1",//服務器名稱 }; app.UseHangfireServer(jobOptions);//啟動Hangfire服務 app.UseHangfireDashboard();//啟動hangfire面板 backgroundJobs.Enqueue(() => Console.WriteLine("Hangfire 服務器已啟動")); app.UserHangfireAdminService(service); //這個是自己寫的服務擴展
jobOptions如果不配置,會有自己默認的名稱,例如服務器會讀取你當前系統的名稱,隊列那些會讀取對應服務器的程序集名稱。
3.寫服務
完成了第一二步,這里看這個作業如何寫
public static class HangfireAdminService { private static BackgroundJobServer _server; /// <summary> /// 使用后台作業 /// </summary> /// <param name="app"></param> /// <param name="service"></param> /// <param name="client"></param> /// <returns></returns> public static IApplicationBuilder UserHangfireAdminService(this IApplicationBuilder app, IConferenceService service) { var mcfg = service.MailConfigDefault(); BackgroundJob.Enqueue(() => Console.WriteLine($"測試單個作業: {DateTime.Now}")); RecurringJob.AddOrUpdate( () => Console.WriteLine($"測試循環作業: {DateTime.Now}"), Cron.Minutely ); BackgroundJob.Schedule(() => Console.WriteLine($"測試延遲作業: {DateTime.Now}"), TimeSpan.FromMinutes(1)); return app; } }
這個是剛才configure里面的方法。 可以寫成一個IApplicationBuilder的擴展方法,加進管道
這樣服務器啟動時,就會啟動里面的服務。
如果Job作業需要調用一個后台服務,就不能直接在里面_service.Log這樣去調用方法了,因為處於不同的線程方式。所以job調后台,可以這樣操作
舉例,這是個api發郵件的方法
/// <summary> /// 發送郵件 /// </summary> /// <param name="mail"></param> [HttpPost] [Route("SendPwd")] public MsgResult<bool> SendPwd(MailConfigDto mail) { MsgResult<bool> result = new MsgResult<bool>(ResultCode.Success); UserAccountDto user = null; try { MailConfigDto defaultMail = _service.MailConfigDefault(); user = _service.UserDtoById(mail.ExtensionId); defaultMail.Body = $"用戶注冊成功!登錄名是:{user.UserName},登錄密碼是:{user.Password},注冊類型是:{user.CustomerProfileName}"; defaultMail.Subject = $"用戶:{user.Name}注冊成功!"; List<KeyValuePair<string, string>> To = new List<KeyValuePair<string, string>>() { new KeyValuePair<string, string>(user.Name,user.Email) }; defaultMail.To = To; SendEmail(defaultMail); BackgroundJob.Enqueue<IConferenceService>((s) => s.LogAdd("注冊成功", $"用戶{user.Name}注冊成功,已發送郵件", OPLog.AdminLogin) ); } catch (Exception ex) { result = new MsgResult<bool>(ResultCode.Exception, ex.Message); } return result; }
關鍵點, BackgroundJob.Enqueue<IConferenceService>((s) =>s.LogAdd());
Enqueue有個泛型的重載,這里等於是依賴注入的方式,因為在全局autofac配置過
IConferenceService是指向ConferenceService服務的,所以這里注入了Enqueue<IConferenceService>接口,只能是接口,才可以讓DI生效。
so, s.LogAdd代表了接口里面的方法。這樣Enqueue里面就可以調用后台自定義的服務了
4.總結,當然還有很多細節沒談,不過這樣基本的配置和使用,已經滿足軟件的日常用途了。
補充一點,常用的三種方式的特點,
立即執行,完事后會自動銷毀,當然,失敗了按默認的1分鍾后會重新嘗試,直到成功了
延遲執行,這個等於制定了計划的執行時間,這里最少時間是按分鍾算,所以這里不能按用秒甚至毫秒做計算時間的任務。
循環執行,循環執行獨立一個方法 RecurringJob。如果大類分,前2個是一個后台作業類,這個獨立的類。循環執行某次進程如果失敗了,也不會影響整體的循環效果,只是失敗的進程也會按總體的規則,1分鍾后重新嘗試失敗的進程。
當然還有其他的,例如批量處理,延續,批量延續等