Asp-Net-Core開發筆記:集成Hangfire實現異步任務隊列和定時任務

前言最近把Python寫的數據采集平臺往.Net Core上遷移 , 原本的采集任務使用多進程+線程池的方式來加快采集速度,使用Celery作為異步任務隊列兼具定時任務功能,這套東西用著還行,但反正就折騰嘛,直接上C#~

本文記錄 Hangfire 在實際應用里的用法,我發現網絡上找到的大部分文章都是用 Hangfire 的異步任務輸出個 Hello World,然后就沒了 。我實在不知道這樣的文章寫了有什么意義??除了浪費看的人的時間之外,還浪費自己寫文章的時間……
.NetCore作為一個高性能的平臺,自然不可能輸給Python,不過我不想造輪子了(菜),找個現成的方案來用,免得踩坑~
先是調研了一下.NetCore目前的生態,發現有幾個選擇:
  • FreeScheduler
  • Quartz.net
  • Hangfire
第一個 FreeScheduler 和 FreeSQL 項目出自同一個作者之手 , 剛好我的項目也是用的 FreeSQL 作為 ORM,不過看了一下Github上stars比較少,而且文檔暫時還不完善,我最關心的依賴注入功能暫時還不好搞,于是只好作罷 。
然后在 Quartz.net 和 Hangfire 兩者中,我選擇了后者,原因是我之前做 CrawlCenterNet 項目的時候用過 Hangfire,還挺好用的,且帶有一個簡單的 dashboard,比較直觀~
那么就開始吧~
關于后端的選擇這里的后端指的是任務隊列的存儲后端,也就是 Hangfire 文檔中寫的 Storage 。
看了一下官網,大部分關系型非關系型數據庫都是可以的,那我就放心了 。由于目前生產環境在使用 Oracle 數據庫,所以一開始我選擇了 Oracle 作為 Storage,但是在同時開到2000多個任務的時候報錯了,看了下原因是表空間不足,是 Oracle 的問題…
所以為了性能和穩定性,我棄坑了,接著嘗試了 SQLite (僅作為本地測試),結果發現配置里面定義了 Connection String 但它不理我,直接把這個 Connection String 作為數據庫的名稱了 , 無語… 這樣就沒辦法把 SQLite 數據庫設置為異步模式 , 那速度就直接烏龜爬了…
再次棄坑… 這次直接上 Redis 了,為了提高性能,舍棄持久化能力~ Redis也沒讓我失望,幾千個任務壓根不帶眨眼的,nice~
數據采集代碼Hangfire 組件不是一開始就引入的,這里先上最基本的數據采集代碼,后面的介紹才能更清楚~
關鍵的代碼在 Services/CrawlService.cs 文件中
public class CrawlService {// 依賴注入一些服務private readonly IBaseRepository<Proc> _repo;public async Task CrawlAllProc() {for(var i=1; i<2000; i++) {await CrawlProcList(i);}}public async Task CrawlProcList(int page) {// 具體代碼省略了var procList = ; //...foreach (var proc in procList) {await CrawlProc(proc);}}public async Task CrawlProc(Proc proc) { }}然后,當啟動采集任務的時候,直接去調用 CrawlAllProc 方法,這樣就開始一頁一頁采集 , 每頁又有很多的 Proc 數據,全都采集下來 。
上面的代碼用的是 await,會等待異步方法完成,速度很慢,去掉 await ,在新線程中執行任務,不等待其結束,不過問題也很明顯,如果出錯了很難調試,這樣就不好保證系統的穩定性 。
接下來我們用 Hangfire 來改造 。
安裝 Hangfire本項目用到了以下依賴:
  • Hangfire.Core
  • Hangfire.AspNetCore
  • Hangfire.Redis.StackExchange
直接 nuget 一把梭完事
注冊服務為了跟后面的內容區分,這里先來官方的例子
注冊服務:
services.AddHangfire(configuration => configuration.SetDataCompatibilityLevel(CompatibilityLevel.Version_170).UseSimpleAssemblyNameTypeSerializer().UseRecommendedSerializerSettings()// 根據實際使用的 Storage 來注冊.UseRedisStorage();services.AddHangfireServer();添加中間件:
app.UseHangfireDashboard();簡單使用Hangfire 注冊的時候默認是單例模式,所以在任意代碼中使用其靜態方法就能添加異步任務或者定時任務 。
異步任務:
BackgroundJobs.Enqueue(() => Console.WriteLine("Hello world!"));定時任務:
Hangfire的定時任務叫做 recurrent tasks,我之前一般習慣叫 scheduled task,一開始差點找不到文檔~
以下代碼添加一個每天執行一次的任務 , 如果需要其他時間 , 可以自定義后面的 Cron 參數 , 具體自行研究 Cron 語法~
RecurringJob.AddOrUpdate("easyjob", () => Console.Write("Easy!"), Cron.Daily);正經使用OK , 終于進到正文
正如我一開始說的 , 前面介紹的用法是遠遠不夠的,如果只是介紹個 Hello World,那也沒必要專門寫篇文章了…

推薦閱讀