net core WebApi——定時任務Quartz

来源:https://www.cnblogs.com/AprilBlank/archive/2019/09/27/11595603.html
-Advertisement-
Play Games

[toc] 前言 本來打算昨天都開始寫這篇,就因為要把小團隊的博客整理彙總,一看二哈的博客那麼多,一個個複製粘貼肯定麻煩(其實是我自己覺得複製麻煩),所以穿插著寫了個小爬蟲,後續寫差不多了就拿出來晾晾吧(py菜雞水平)。 之前開發的時候,忽略了記錄,等到想寫點兒啥跟後臺有關的東西的時候,還得一點點回 ...


目錄

前言

本來打算昨天都開始寫這篇,就因為要把小團隊的博客整理彙總,一看二哈的博客那麼多,一個個複製粘貼肯定麻煩(其實是我自己覺得複製麻煩),所以穿插著寫了個小爬蟲,後續寫差不多了就拿出來晾晾吧(py菜雞水平)。

之前開發的時候,忽略了記錄,等到想寫點兒啥跟後臺有關的東西的時候,還得一點點回憶,最近是因為同事給我說,"哎,每個月把數據給我統計下做個界面展示啊"。一想到每個月我要做次操作就頭疼,咦,不對,這不就是寫個定時任務就搞定了嘛。

Quartz

其實在選這個定時器的類庫的時候,我在Hangfire兩者間徘徊,後來是想到不管用什麼方法什麼工具都是次要的,主要看你怎麼用,用到哪,圖形界面是需要但不是必要,分秒級別的控制也都是看你自己業務需要,定時器就後臺掛起運行就行了沒必要讓我看見,想操作了再說吧,就這樣愉快的決定使用Quartz

首先,依然是在我們Util的工程引入包。

引入完成後,在我們的入口Startup中添加實例的註冊聲明。

        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            ServiceInjection.ConfigureRepository(services);

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
            //任務調度
            services.TryAddSingleton<ISchedulerFactory, StdSchedulerFactory>();
        }

SchedulerFactory任務調度就好比一個公司的老大,Trigger就是一個項管,Job就是苦逼的碼農,老大想要一天搞個app,就跟項管說一句,我要一天後要東西,這時候項管心裡就有數了,一天後的那個時間,找到碼農,直接剝奪他的代碼執行,好了app出來了,苦逼的結束並不意味著真的結束,這老大一看可以啊,好了,以後每天我要一個成品app,如此迴圈往複,項管不厭其煩,碼農換了又換(當然job不會)。

項管還會有多個,每個項管下麵可不止一個碼農。

像這樣的情況可能有些誇張,但是類似的情況卻真實存在。

ok,完了之後,我們來創建一個MyJob

    public class MyJob : IJob
    {
        public Task Execute(IJobExecutionContext context)
        {
            return Task.Run(() =>
            {
                LogUtil.Debug("執行MyJob");
            });
        }
    }

之後我們來寫個簡單的QuartzUtil

    public class QuartzUtil
    {
        private static ISchedulerFactory _schedulerFactory;
        private static IScheduler _scheduler;

        /// <summary>
        /// 添加任務
        /// </summary>
        /// <param name="type">類</param>
        /// <param name="jobKey">鍵</param>
        /// <param name="trigger">觸發器</param>
        public static async void Add(Type type, JobKey jobKey, ITrigger trigger = null)
        {
            Init();
            _scheduler = await _schedulerFactory.GetScheduler();

            await _scheduler.Start();

            if (trigger == null)
            {
                trigger = TriggerBuilder.Create()
                    .WithIdentity("april.trigger")
                    .WithDescription("default")
                    .WithSimpleSchedule(x=>x.WithMisfireHandlingInstructionFireNow().WithRepeatCount(-1))
                    .Build();
            }
            var job = JobBuilder.Create(type)
                .WithIdentity(jobKey)
                .Build();

            await _scheduler.ScheduleJob(job, trigger);          
        }
        /// <summary>
        /// 恢復任務
        /// </summary>
        /// <param name="jobKey">鍵</param>
        public static async void Resume(JobKey jobKey)
        {
            Init();
            _scheduler = await _schedulerFactory.GetScheduler();
            LogUtil.Debug($"恢復任務{jobKey.Group},{jobKey.Name}");
            await _scheduler.ResumeJob(jobKey);
        }
        /// <summary>
        /// 停止任務
        /// </summary>
        /// <param name="jobKey">鍵</param>
        public static async void Stop(JobKey jobKey)
        {
            Init();
            _scheduler = await _schedulerFactory.GetScheduler();
            LogUtil.Debug($"暫停任務{jobKey.Group},{jobKey.Name}");
            await _scheduler.PauseJob(jobKey);
        }
        /// <summary>
        /// 初始化
        /// </summary>
        private static void Init()
        {
            if (_schedulerFactory == null)
            {
                _schedulerFactory = AprilConfig.ServiceProvider.GetService<ISchedulerFactory>();
            }
        }
    }

觸發器的使用,有很多種方式,可以使用簡單的執行一次/多久執行一次/迴圈執行幾次等等。

還有可以使用Cron表達式:

簡單來說,corn從左到右(用空格隔開):秒 分 小時 月份中的日期 月份 星期中的日期 年份,舉個例子,就像開頭說的,讓我每隔一個月執行一次統計,寫法就是 0 0 0 1 * ?,當然這就有涉及到什麼符號的問題了,這種不需要強記,需要的時候查下就行,推薦一個工具站吧,Cron校驗工具

測試

感覺我的博客內容好單調,內容框架就是開頭,代碼,測試,結尾,唉

不過做啥東西,測試少不了,最起碼你的東西能用,才說明可行。

我們在Values添加一個方法,這裡我們5s一執行(懶得等)。

        [HttpGet]
        [Route("QuartzTest")]
        public void QuartzTest(int type)
        {
            JobKey jobKey = new JobKey("demo","group1");
            switch (type)
            {
                //添加任務
                case 1:
                    var trigger = TriggerBuilder.Create()
                            .WithDescription("觸發器描述")
                            .WithIdentity("test")
                            //.WithSchedule(CronScheduleBuilder.CronSchedule("0 0/30 * * * ? *").WithMisfireHandlingInstructionDoNothing())
                            .WithSimpleSchedule(x=>x.WithIntervalInSeconds(5).RepeatForever().WithMisfireHandlingInstructionIgnoreMisfires())
                            .Build();
                    QuartzUtil.Add(typeof(MyJob), jobKey, trigger);
                    break;
                //暫停任務
                case 2:
                    QuartzUtil.Stop(jobKey);
                    break;
                //恢復任務
                case 3:
                    QuartzUtil.Resume(jobKey);
                    break;
            }
        }

讓我們來愉快的運行吧,記得appsettings配置個路徑訪問白名單。

測試

一番1,2,3輸入完之後,我們來看下日誌。
測試

  • 執行任務--- ok
  • 暫停任務--- ok
  • 恢復任務--- ok

問題及解決方法

但是問題出現了,暫停恢復後,連執行了多次(具體看你間隔時間以及你的頻率),這個是有點兒怪異,當時我記得這個問題讓我鼓搗了好半天,也是各種查資料查方法,但實際呢這個是Quartz的保護機制,為了防止你的操作是因為不可預知的問題導致的,所以有個重做錯過的任務,另外我們的代碼中觸發器也有這個配置WithMisfireHandlingInstructionIgnoreMisfires

我們來去掉這個重做機制並測試。

測試

CronTrigger

規則 介紹
withMisfireHandlingInstructionDoNothing 不觸發立即執行; 等待下次Cron觸發頻率到達時刻開始按照Cron頻率依次執行
withMisfireHandlingInstructionIgnoreMisfires 以錯過的第一 個頻率時間立刻開始執行; 重做錯過的所有頻率周期後; 當下一次觸發頻率發生時間大於當前時間後,再按照正常的Cron頻率依次執行
withMisfireHandlingInstructionFireAndProceed 以當前時間為觸發頻率立刻觸發一次執行; 然後按照Cron頻率依次執行

SimpleTrigger

規則 介紹
withMisfireHandlingInstructionFireNow 以當前時間為觸發頻率立即觸發執行; 執行至FinalTIme的剩餘周期次數;以調度或恢復調度的時刻為基準的周期頻率,FinalTime根據剩餘次數和當前時間計算得到; 調整後的FinalTime會略大於根據starttime計算的到的FinalTime值
withMisfireHandlingInstructionIgnoreMisfires 以錯過的第一個頻率時間立刻開始執行; 重做錯過的所有頻率周期;當下一次觸發頻率發生時間大於當前時間以後,按照Interval的依次執行剩下的頻率; 共執行RepeatCount+1次
withMisfireHandlingInstructionNextWithExistingCount 不觸發立即執行; 等待下次觸發頻率周期時刻,執行至FinalTime的剩餘周期次數; 以startTime為基準計算周期頻率,並得到FinalTime; 即使中間出現pause,resume以後保持FinalTime時間不變
withMisfireHandlingInstructionNowWithExistingCount 以當前時間為觸發頻率立即觸發執行; 執行至FinalTIme的剩餘周期次數; 以調度或恢復調度的時刻為基準的周期頻率,FinalTime根據剩餘次數和當前時間計算得到; 調整後的FinalTime會略大於根據starttime計算的到的FinalTime值
withMisfireHandlingInstructionNextWithRemainingCount 不觸發立即執行; 等待下次觸發頻率周期時刻,執行至FinalTime的剩餘周期次數; 以startTime為基準計算周期頻率,並得到FinalTime; 即使中間出現pause,resume以後保持FinalTime時間不變
withMisfireHandlingInstructionNowWithRemainingCount 以當前時間為觸發頻率立即觸發執行; 執行至FinalTIme的剩餘周期次數; 以調度或恢復調度的時刻為基準的周期頻率,FinalTime根據剩餘次數和當前時間計算得到; 調整後的FinalTime會略大於根據starttime計算的到的FinalTime值

配置規則介紹參考:https://blog.csdn.net/yangshangwei/article/details/78539433

之前在net framework遇到過一個問題,IIS回收問題,網站在20分鐘無請求後就停了,任務也緊跟著停了,當時的解決方法是做個windows服務來定時請求網站保持活躍,當然也可以通過禁止回收來保持網站一直運行。

net core中還沒部署運行,如果有相關問題,後續也會補充上來一起交流解決。

小結

定時任務在一個後臺系統中一般使用場景還算廣泛,主要是sql數據統計,sql/文件備份,定時推送等,具體問題具體分析,net core 3.0都已經問世了,學無止境啊。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 微信小程式支付 1、背景 因業務需要接入微信支付功能(客戶端是微信小程式),因公司伺服器版本較低,服務端採用.Net Framework 版本(並採用盛派微信SDK) 2、文檔地址 1)小程式支付:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api. ...
  • 這邏輯,強無敵! 只要你載入一次,就別想再載入第二次。 ...
  • <Grid HorizontalAlignment="Center" VerticalAlignment="Center"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition/> </Grid.RowDefinit... ...
  • 前提 入行已經7,8年了,一直想做一套漂亮點的自定義控制項,於是就有了本系列文章。 GitHub:https://github.com/kwwwvagaa/NetWinformControl 碼雲:https://gitee.com/kwwwvagaa/net_winform_custom_contr ...
  • 今天寫代碼發現有些代碼行參差不齊,空行又多,整理看起來醜的不行,於是上網搜了下代碼整理的快捷方式以作記錄 這是整理之前,亂糟糟的(故意打亂為了節目效果) 第一步:Ctrl+a (全選代碼) 第二步:Ctrl+K+F(整理代碼) 是不是整齊多了,但是你以為這樣就完了嗎?不不不,這些空行難道不醜嗎? 第 ...
  • System.Text.Json處理Json文檔需要用到JsonDocument,JsonElement,JsonProperty。 JsonDocument代表一個Json文檔,JsonElement就是Json的元素集合。 處理Json文檔時基本是對JsonElement和JsonPropert ...
  • 最近遇到一個.NET連接Oracle的一個錯誤,其主要原因是換了一臺電腦,在新電腦上運行以前的項目出現了的一個錯誤,工作環境為vs2017+Oracle 64位,win10系統 這個錯誤頭疼了一天,找了好多博客去解決這個問題 在這主要是總結一下本人的解決思路與方法。 1.查看自己的Oracle客戶端 ...
  • 前言 OAuth 2.0預設四種授權模式(GrantType) 授權碼模式(authorization_code) 簡化模式(implicit) 密碼模式(resource owner password credentials) "客戶端模式(client_credentials)" 本章主要介紹客 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...