文主要說明ABP中后台工作者模塊(BackgroundWorker)的實現方式,和后台工作模塊(BackgroundJob)。ABP通過BackgroundWorkerManager來管理BackgroundJobManager,然后通過BackgroundJobManager來管理BackgroundJob。BackgroundJob就代表一個真正的后台任務。
這兩個模塊是在ABPKernelModule的PostInitialize完成初始化的。
后台工作者模塊
首先瀏覽下后台工作者模塊所涉及到的接口和類。其中BackgroundJobManager屬於后台工作模塊。其繼承自后台工作者模塊中的PeriodicBackgroundWorkerBase。
逐個分析這些類和接口
IRunnable/RunnableBase: 定義了啟動/終止一個任務的方法的接口和基本實現。共三個方法:start, stop, waittostop. start和stop這兩個方法很容易理解,就是啟動和終止一個任務。后文再解釋waittostop方法。
IBackgroundWorker:沒有添加任何新方法,這個接口僅用於標識其對應的實現是一個后台工作任務類,用於在后台執行一些任務。
BackgroundWorkerBase:實現IBackgroundWorker的一個抽象類,同時添加了UOW,Setting 和本地化的一些輔助方法。
IBackgroundWorkerManager/BackgroundWorkerManager: 用於管理后台工作任務 - IBackgroundWorker實例(添加IBackgroundWorker實例到管理器,啟動,終止和注銷后台任務)。設計一個***Manager接口和類是ABP中設計各個功能塊的慣用思路,起到了對外隱藏實現細節的作用,可以認為是Facade設計模式的運用。
PeriodicBackgroundWorkerBase:通過封裝AbpTimer實現定時啟動執行任務的功能。這個類型定義個一個抽象方法DoWork. AbpTimer最終會定時執行這個方法。
AbpTimer是整個ABP框架實現后台工作的核心類,其實現原理就是通過一個CLR中的timer定時啟動執行任務。這里有兩個要點值得留意:
第一,用timer有一個弊端,就是當timer間隔時間內,任務如果沒執行完,timer就會新建一個線程,從頭開始執行這個任務,而上一個線程仍然繼續執行,這樣就會導致系統中產生的線程過多,一會兒系統的資源就耗盡了。ABP的解決思路是在執行真正的業務方法之前,通過將timer的duetime設為無限大,從而timer就失效了。業務方法執行完以后在恢復timer的設置。
第二,如何知道一個Timer真正結束了呢?也就是說如何知道一個Timer要執行的任務已經完成(這里定義為A效果),同時timer已失效(這里定義為B效果)?ABP通過stop方法實現B,通過WaitToStop實現A效果。WaitToStop會一直阻塞調用他的線程直到_performingTasks變成false,也就是說Timer要執行的任務已經完成(任務完成時會將_performingTasks設為False,並且釋放鎖)。
后台工作模塊
首先瀏覽下涉及到的接口和類。
BackgroundJobInfo: 用於持久化job信息的實體類,對應於數據庫中的表AbpBackgroundJobs。這個實體類有以下屬性。一個job對應一個要執行的任務。他又兩個很關鍵的屬性JobArgs和JobType。其JobType就是接下來要介紹的IBackgroundJob實例的類型。IBackgroundJobManager最終就是根據這個JobType通過反射恢復出IBackgroundJob實例的。JobArgs就是傳入IBackgroundJob實例的Execute方法的實參(這里會被序列化后在賦值給BackgroundJobInfo)。
IBackgroundJob/BackgroundJob:定義一個后台工作任務的接口/和基本實現。具體的后台任務類可從BackgroundJob繼承,這是定義最終需要被執行的邏輯的地方。
IBackgroundJobConfiguration/BackgroundJobConfiguration: 配置是否激活后台工作任務功能。
BackgroundJobPriority:后台job的優先級
IBackgroundJobStore/InMemoryBackgroundJobStore: 用於持久化后台任務BackgroundJobInfo。可以實現這個接口將后台任務BackgroundJobInfo存儲到數據庫。或者你可以使用module-zero,它已經實現了IBackgroundJobStore。如果你正在使用第三方的工作管理者(像Hangfire),那么不需要實現IBackgroundJobStore。
IBackgroundJobManager/BackgroundJobManager, IBackgroundJobManager默認是由BackgroundJobManager實現的。它可以被其他的后台工作提供者替代(Hangfire)。 BackgroundJobManager之所以能在后台執行任務,是因為其繼承了PeriodicBackgroundWorkerBase基類,並重寫了DoWork方法。
BackgroundJobManager:是PeriodicBackgroundWorkerBase一個派生類,其具體實現了DoWork方法:從BackgroundJobStore(可以自定義實現從數據庫中讀取)取最多1000個BackgroundJobInfo,然后反射執行BackgroundJobInfo中定義的任務。
下面是一個ABP中通過BackgroundJobManager安排BackgroundJob的例子。