返回總目錄:ABP+AdminLTE+Bootstrap Table權限管理系統一期
HangFire與Quartz.NET相比主要是HangFire的內置提供集成化的控制檯,方便後臺查看及監控,對於你們來講,比較方便。html
Hangfire是一個開源框架(.NET任務調度框架),能夠幫助您建立,處理和管理您的後臺做業,處理你不但願放入請求處理管道的操做:git
Hangfire支持全部類型的後臺任務 - 短期運行和長時間運行, CPU intensive
和I/O intensive
,一次性的和常常性的。你不須要從新發明輪子 ,能夠直接使用。
Hangfire包含三大核心組件:客戶端、持久化存儲、服務端。看看官方的這張圖:github
var jobId = BackgroundJob.Schedule( () => Console.WriteLine("Delayed!"), TimeSpan.FromDays(7));
RecurringJob.AddOrUpdate( () => Console.WriteLine("Recurring!"), Cron.Daily);
Task
,能夠在第一個任務執行完以後緊接着再次執行另外的任務:BackgroundJob.ContinueWith( jobId, () => Console.WriteLine("Continuation!"));
var jobId = BackgroundJob.Schedule( () => Console.WriteLine("Delayed!"), TimeSpan.FromDays(7));
var batchId = Batch.StartNew(x => { x.Enqueue(() => Console.WriteLine("Job 1")); x.Enqueue(() => Console.WriteLine("Job 2")); });
Batch.ContinueWith(batchId, x => { x.Enqueue(() => Console.WriteLine("Last Job")); });
public class CleanTempDirectoryProcess : IBackgroundProcess { public void Execute(BackgroundProcessContext context) { Directory.CleanUp(Directory.GetTempDirectory()); context.Wait(TimeSpan.FromHours(1)); } }
後臺做業是應用程序中很是重要的部分,Hangfire
確保至少執行一次任務。要在應用程序從新啓動之間保留後臺做業信息,全部信息都將保存在您最喜歡的持久性存儲中。
Hangfire將您的任務保存到持久化庫彙總,而且以可靠的方式處理它們。這意味着,你能夠中斷Hangfire Worder
的線程,從新加載應用程序域,或者終止程序,即便這樣您的任務仍會被處理。只有在你代碼的最後一行執行完成,Hangfire
纔會標記這個任務完成。而且知道任務可能在最後一行代碼執行以前失敗。它包含多種 自動-重試機制,它能夠自動處理在存儲或代碼執行過程當中發生的錯誤。
這對於通用託管環境(如IIS Server)很是重要。它們能夠包含不的
優化,超時和錯誤處理代碼 (可能致使進程終止)來防止很差的事情發生。若是您沒有使用可靠的處理和自動機制,您的工做可能會丟失。您的最終用戶可能無限期等待某些任務,如電子郵件,報告,通知等。web
光說不練假把式,下面咱們新建一個web項目,而後NuGet引入這幾個程序集
數據庫
而後在App_Start文件夾下Startup類配置下。
首先指定數據庫,指定Hangfire使用內存存儲後臺任務信息.
Hangfire.GlobalConfiguration.Configuration.UseSqlServerStorage("Default");
而後啓用HangfireServer這個中間件(它會自動釋放)
app.UseHangfireServer();
而後啓用Hangfire的儀表盤(能夠看到任務的狀態,進度等信息)
app.UseHangfireDashboard();
而後配置下前臺路由json
app.UseHangfireDashboard("/hangfire", new DashboardOptions { Authorization = new[] { new AbpHangfireAuthorizationFilter() } });
而後就是加入上面已經列出的幾個例子。服務器
var jobId = BackgroundJob.Schedule( () => Console.WriteLine("Delayed!"), TimeSpan.FromDays(7)); RecurringJob.AddOrUpdate( () => Console.WriteLine("Recurring!"), Cron.Daily); BackgroundJob.ContinueWith( jobId, () => Console.WriteLine("Continuation!")); var jobId2 = BackgroundJob.Schedule( () => Console.WriteLine("Delayed!"), TimeSpan.FromDays(7));
運行項目,輸入路徑http://<your-site>/hangfire
而後就能夠看到界面了。
併發
咱們分別點擊上面界面中的「加入隊列」「當即執行按鈕」,就獲得下面這幅圖片。
點擊進去,能夠看到以下圖。
app
界面看起來很清爽,並且一目瞭然。這就是可視化界面的好處。框架
ASP.NET Boilerplate提供後臺做業和後臺工做者,用於在應用程序的後臺線程中執行某些任務。
後臺做業用於排隊某些任務,以隊列和持續的方式在後臺執行。
咱們能夠經過從BackgroundJob <TArgs>
類繼承或直接實現IBackgroundJob <TArgs>
接口來建立後臺做業類。
這是最簡單的後臺工做:
public class TestJob : BackgroundJob<int>, ITransientDependency { public override void Execute(int number) { Logger.Debug(number.ToString()); } }
後臺做業定義了一個Execute方法獲取輸入參數。參數類型被定義爲泛型 類參數,如示例中所示。後臺工做必須註冊到依賴注入系統中,實現ITransientDependency是最簡單的方式。下面定義一個更實際的工做,在後臺隊列中發送電子郵件:
public class SimpleSendEmailJob : BackgroundJob<SimpleSendEmailJobArgs>, ITransientDependency { private readonly IRepository<User, long> _userRepository; private readonly IEmailSender _emailSender; public SimpleSendEmailJob(IRepository<User, long> userRepository, IEmailSender emailSender) { _userRepository = userRepository; _emailSender = emailSender; } public override void Execute(SimpleSendEmailJobArgs args) { var senderUser = _userRepository.Get(args.SenderUserId); var targetUser = _userRepository.Get(args.TargetUserId); _emailSender.Send(senderUser.EmailAddress, targetUser.EmailAddress, args.Subject, args.Body); } }
咱們注入了用戶倉儲(爲了得到用戶信息)和email發送者(發送郵件的服務),而後簡單地發送了該郵件。SimpleSendEmailJobArgs是該工做的參數,它定義以下:
[Serializable] public class SimpleSendEmailJobArgs { public long SenderUserId { get; set; } public long TargetUserId { get; set; } public string Subject { get; set; } public string Body { get; set; } }
做業參數應該是可序列化的,由於它 被序列化並存儲在數據庫中。雖然ASP.NET Boilerplate默認後臺做業管理器使用JSON 序列化(不須要[Serializable]
屬性),但最好定義[Serializable]
屬性,由於未來可能會切換到另外一個做業管理器,在二進制序列化。保持你的參數簡單(如 DTO),不要包含 實體或其餘不可序列化的對象。如SimpleSendEmailJob
示例所示,咱們只能存儲 一個實體的Id,並從做業中的存儲庫獲取該實體。將新做業添加到隊列中定義後臺做業後,咱們能夠注入並使用IBackgroundJobManager
將做業添加到隊列中。查看上面定義的TestJob
示例:
public class MyService { private readonly IBackgroundJobManager _backgroundJobManager; public MyService(IBackgroundJobManager backgroundJobManager) { _backgroundJobManager = backgroundJobManager; } public void Test() { _backgroundJobManager.Enqueue<TestJob, int>(42); } }
當入隊(Enqueue)時,咱們將42做爲參數傳遞。IBackgroundJobManager
將會實例化並使用42做爲參數執行TestJob
。
讓咱們看一下如何爲上面定義的SimpleSendEmailJob
添加一個新的工做:
[AbpAuthorize] public class MyEmailAppService : ApplicationService, IMyEmailAppService { private readonly IBackgroundJobManager _backgroundJobManager; public MyEmailAppService(IBackgroundJobManager backgroundJobManager) { _backgroundJobManager = backgroundJobManager; } public async Task SendEmail(SendEmailInput input) { await _backgroundJobManager.EnqueueAsync<SimpleSendEmailJob, SimpleSendEmailJobArgs>( new SimpleSendEmailJobArgs { Subject = input.Subject, Body = input.Body, SenderUserId = AbpSession.GetUserId(), TargetUserId = input.TargetUserId }); } }
Enqueu
(或EnqueueAsync
)方法具備其餘參數,如優先級 和延遲。
IBackgroundJobManager
由BackgroundJobManager
默認實現。它能夠被另外一個後臺做業提供者替代(參見 hangfire
集成)。有關默認BackgroundJobManager
的一些信息:
這是一個簡單的做業隊列在 單線程中做爲FIFO使用。它使用IBackgroundJobStore
來堅持做業。
默認的BackgroundJobManager
須要一個數據存儲來保存和獲取做業。若是您沒有實現IBackgroundJobStore
,那麼它使用 InMemoryBackgroundJobStore
,它不會將做業保存在持久數據庫中。您能夠簡單地實現它來將做業存儲在數據庫中,或者可使用 已經實現它的module-zero
。
若是您使用第三方工做經理(如 Hanfgire
),則無需實施IBackgroundJobStore
。
您能夠在 模塊的PreInitialize
方法中使用Configuration.BackgroundJobs
來配置後臺做業系統。
禁用做業執行
您可能須要爲應用程序禁用後臺做業執行:
public class MyProjectWebModule : AbpModule { public override void PreInitialize() { Configuration.BackgroundJobs.IsJobExecutionEnabled = false; } //... }
這種狀況不多見。可是,認爲您正在同一個數據庫上運行應用程序的多個實例(在Web場中)。在這種狀況下,每一個應用程序將查詢做業的相同數據庫並執行它們。這致使同一個工做的多個執行和一些其餘問題。爲了防止它,你有兩個選擇:
因爲默認的後臺做業管理器應該從新嘗試失敗的做業,它會處理(並記錄)全部異常。若是你想在發生異常時獲得通知,你能夠建立一個事件處理程序來處理AbpHandledExceptionData
。後臺管理器用一個包裝了真正異常的BackgroundJobException
異常對象觸發這個事件(對於實際的異常,獲得InnerException
)。
要建立一個後臺工做者,咱們應該實現 IBackgroundWorker
接口。或者,咱們能夠根據咱們的須要從BackgroundWorkerBase
或PeriodicBackgroundWorkerBase
繼承 。
假設咱們想在最近30天內沒有登陸到應用程序,使用戶狀態passive。看代碼:
public class MakeInactiveUsersPassiveWorker : PeriodicBackgroundWorkerBase, ISingletonDependency { private readonly IRepository<User, long> _userRepository; public MakeInactiveUsersPassiveWorker(AbpTimer timer, IRepository<User, long> userRepository) : base(timer) { _userRepository = userRepository; Timer.Period = 5000; //5 seconds (good for tests, but normally will be more) } [UnitOfWork] protected override void DoWork() { using (CurrentUnitOfWork.DisableFilter(AbpDataFilters.MayHaveTenant)) { var oneMonthAgo = Clock.Now.Subtract(TimeSpan.FromDays(30)); var inactiveUsers = _userRepository.GetAllList(u => u.IsActive && ((u.LastLoginTime < oneMonthAgo && u.LastLoginTime != null) || (u.CreationTime < oneMonthAgo && u.LastLoginTime == null)) ); foreach (var inactiveUser in inactiveUsers) { inactiveUser.IsActive = false; Logger.Info(inactiveUser + " made passive since he/she did not login in last 30 days."); } CurrentUnitOfWork.SaveChanges(); } } }
這是現實的代碼,能夠直接在module-zero
的 ASP.NET Boilerplate中運行 。
PeriodicBackgroundWorkerBase
派生(如本示例中所示),則應該實施DoWork
方法來執行您的按期工做代碼。BackgroundWorkerBase
派生或直接實現IBackgroundWorker
,則將覆蓋/實現Start
,Stop
和WaitToStop
方法。Start
和Stop
方法應該是非阻塞的,WaitToStop
方法應該等待 worker
完成當前的關鍵任務。建立後臺工做者後,咱們應該將其添加到 IBackgroundWorkerManager
。最多見的地方是你的模塊的PostInitialize
方法:
public class MyProjectWebModule : AbpModule { //... public override void PostInitialize() { var workManager = IocManager.Resolve<IBackgroundWorkerManager>(); workManager.Add(IocManager.Resolve<MakeInactiveUsersPassiveWorker>()); } }
雖然咱們一般在PostInitialize
中加入工做人員,但對此沒有限制。您能夠在任何地方注入IBackgroundWorkerManager
,並在運行時添加工做人員。當您的應用程序正在關閉時,IBackgroundWorkerManager
將中止並釋放全部註冊的工做人員。
後臺工做人員一般以單例的。可是沒有限制。若是您須要同一工人類的多個實例,則能夠將其設置爲暫時的,並向IBackgroundWorkerManager
添加多個實例。在這種狀況下,您的工做人員多是參數化的(例如,您有一個LogCleaner
類,可是他們監視的兩個LogCleaner
工做者實例並清除不一樣的日誌文件夾)。
ASP.NET Boilerplate的後臺工做系統很簡單。除了按期運行的工人以外,它沒有一個時間表系統。若是您須要更高級的計劃功能,咱們建議您檢查Quartz
或其餘庫。
後臺做業和工做人員只有在您的應用程序正在運行時纔有效 若是很長一段時間沒有對Web應用程序執行任何請求,ASP.NET應用程序將默認關閉。所以,若是您在Web應用程序中託管後臺做業(這是默認行爲),則應確保您的Web應用程序配置爲始終運行。不然,後臺做業只在您的應用程序正在使用時才起做用。
有一些技術來完成這一點。最簡單的方法是按期從外部應用程序請求您的Web應用程序。所以,您也能夠檢查您的Web應用程序是否已啓動並正在運行。 Hangfire文檔解釋了其餘一些方法。
經過以上官方文檔,咱們在程序裏配置一下。
運行一下效果是同樣的。
Hangfire
是一個後臺可監控的應用,不用每次都要從服務器拉取日誌查看,在沒有ELK的時候至關不方便。Hangfire
控制面板不只提供監控,也能夠手動的觸發執行定時任務。若是在定時任務處理方面沒有很高的要求,好比必定要5s定時執行,Hangfire
值得擁有。拋開這些,Hangfire
優點太明顯了:
Job Queue
處理任務job
執行併發數控制IOC
、Hangfire Dashboard
受權控制、Asp.net Core
、持久化存儲等Hangfire擴展性你們能夠參考這裏,有幾個擴展是很實用的.下面這些關於Hangfire擴展你們能夠本身查資料。後面若是有機會的話,我再補上。
其實Hangfire仍是蠻簡單的。若是你須要瞭解更多關於Abp.Hangfire的內容,建議你去看一下github上一個專門關於Abp.Hangfire的demo,
地址:https://github.com/aspnetboilerplate/aspnetboilerplate-samples/tree/master/BackgroundJobAndNotificationsDemo
另外 ABP後臺工做者類使用HANGFIRE這篇文章
講解abp Hangfire 缺點是工做者類依賴了具體的基類(PeriodicBackgroundWorkerBase),就會存在應用程序耦合。以及解決耦合的辦法,算是對abp Hangfire的擴展,我不太認同,各有見解吧。
就以上面我說到的項目 abp Hangfire demo 項目 BackgroundJobAndNotificationsDemo爲例,首先是一個建立郵件發送的任務。
,建立到數據庫以後,HangFire會自動在數據庫建立幾張表。
而後配置我上面說到的幾個配置步驟以後。運行項目能夠看到。每隔5秒鐘會請求一下後臺任務。
界面上就有了相應的效果
你們能夠自行下載Demo下來看一下相關的寫法以及配置。
本文githubd地址:https://github.com/Jimmey-Jiang/ABP-ASP.NET-Boilerplate-Project-CMS.git
後臺工做者HangFire與ABP框架Abp.Hangfire及擴展
返回總目錄:ABP+AdminLTE+Bootstrap Table權限管理系統一期