1. 程式人生 > >Asp.Net Core 使用Quartz基於界面畫接口管理做定時任務

Asp.Net Core 使用Quartz基於界面畫接口管理做定時任務

進程終止 val rom ota exc 條件判斷 enume 支持 out

今天抽出一點點時間來造一個小輪子,是關於定時任務這塊的。

這篇文章主要從一下幾點介紹:

  1. 創建數據庫管理表
  2. 創建web項目
  3. 引入quarzt nuget 包
  4. 寫具體配置操作,實現定時任務處理

第一步:創建一個空web項目,引入quarzt nuget 包

技術分享圖片

創建TB.AspNetCore.Quartz web項目和TB.AspNetCore.Data 類庫,在web項目中引入Quartz nuget包

第二部:數據庫創建一張管理表

技術分享圖片

-- ----------------------------
-- Table structure for ScheduleInfo
-- ---------------------------- DROP TABLE IF EXISTS `ScheduleInfo`; CREATE TABLE `ScheduleInfo` ( `Id` int(11) NOT NULL AUTO_INCREMENT COMMENT 編號, `JobGroup` varchar(100) NOT NULL DEFAULT ‘‘ COMMENT 任務組, `JobName` varchar(50) NOT NULL DEFAULT ‘‘ COMMENT 任務名, `RunStatus` int(11) NOT
NULL DEFAULT 0 COMMENT 運行狀態, `CromExpress` varchar(40) NOT NULL DEFAULT ‘‘ COMMENT Crom表達式, `StarRunTime` datetime DEFAULT NULL COMMENT 開始運行時間, `EndRunTime` datetime DEFAULT NULL COMMENT 結束運行時間, `NextRunTime` datetime DEFAULT NULL COMMENT 下次運行時間, `Token` varchar(40) NOT NULL
DEFAULT ‘‘ COMMENT Token, `AppID` varchar(40) NOT NULL DEFAULT ‘‘ COMMENT AppID, `ServiceCode` varchar(40) DEFAULT NULL, `InterfaceCode` varchar(40) DEFAULT NULL, `TaskDescription` varchar(200) DEFAULT NULL, `DataStatus` int(11) DEFAULT NULL COMMENT 數據狀態, `CreateAuthr` varchar(30) DEFAULT NULL COMMENT 創建人, `CreateTime` datetime DEFAULT NULL COMMENT 創建時間, PRIMARY KEY (`Id`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

創建數據庫的表結構如圖所示,接下來我們在Data項目裏添加mysql數據庫驅動nuget包

技術分享圖片

技術分享圖片

打開PM,執行數據庫反向工程命令,從數據庫生成model實體

Scaffold-DbContext "Server=你的服務器地址;Database=你的數據庫;User=數據庫用戶名;Password=你的數據庫密碼;" "Pomelo.EntityFrameworkCore.MySql" -OutputDir Entity

**2.1.1 建議不要選用,防坑!

技術分享圖片

將鏈接字符串換成你自己的,我們又新添加了一個service文件夾和一個Enum文件夾

技術分享圖片

其中,BaseService 裏封裝了針對數據操作的基本crud,quartz裏封裝了關於定時任務的配置,enum裏枚舉了任務狀態,具體代碼如下

public enum JobStatus
    {
        [Description("已啟用")]
        已啟用,
        [Description("運行中")]
        待運行,
        [Description("執行中")]
        執行中,
        [Description("執行完成")]
        執行完成,
        [Description("執行任務計劃中")]
        執行任務計劃中,
        [Description("已停止")]
        已停止,
    }

下面是baseservice裏具體方法

public class BaseService
    {
        protected static object obj = new object();
        public ggb_offlinebetaContext _context;
        protected ggb_offlinebetaContext DataContext
        {
            get
            {
                if (_context == null)
                {
                    _context = new ggb_offlinebetaContext();
                }
                return _context;
            }
        }


        public BaseService()
        {

        }

        #region 封裝基crud
        /// <summary>
        /// 只能是唯一記錄 多記錄引發異常
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public TSource Single<TSource>(Expression<Func<TSource, bool>> predicate = null) where TSource : class
        {
            if (predicate == null)
            {
                return this.DataContext.Set<TSource>().SingleOrDefault();
            }

            return this.DataContext.Set<TSource>().SingleOrDefault(predicate);
        }
        /// <summary>
        /// 查詢一條記錄
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public TSource First<TSource>(Expression<Func<TSource, bool>> predicate = null) where TSource : class
        {
            if (predicate == null)
            {
                return this.DataContext.Set<TSource>().FirstOrDefault();
            }
            return this.DataContext.Set<TSource>().FirstOrDefault(predicate);
        }

        /// <summary>
        /// where條件查詢
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public IQueryable<TSource> Where<TSource>(Expression<Func<TSource, bool>> predicate = null) where TSource : class
        {
            if (predicate == null)
            {
                return this.DataContext.Set<TSource>().AsQueryable();
            }
            return this.DataContext.Set<TSource>().Where(predicate);
        }

        /// <summary>
        /// 記錄數
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public int Count<TSource>(Expression<Func<TSource, bool>> predicate = null)
            where TSource : class
        {
            if (predicate == null)
            {
                return this.DataContext.Set<TSource>().Count();
            }
            return this.DataContext.Set<TSource>().Count(predicate);
        }

        /// <summary>
        /// 根據條件判斷記錄是否存在
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="predicate"></param>
        /// <returns></returns>
        /// Any確定序列是否包含任何元素
        public bool Exists<TSource>(Expression<Func<TSource, bool>> predicate = null) where TSource : class
        {
            if (predicate == null)
            {
                return this.DataContext.Set<TSource>().Any();
            }
            return this.DataContext.Set<TSource>().Any(predicate);
        }

        /// <summary>
        /// 查詢全部
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <returns></returns>
        public IQueryable<TSource> Query<TSource>()
            where TSource : class
        {
            return this.DataContext.Set<TSource>();
        }

        /// <summary>
        /// paging the query 分頁查詢
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="query"></param>
        /// <param name="pageIndex">page index</param>
        /// <param name="pageSize">page size </param>
        /// <param name="count">total row record count</param>
        /// <returns></returns>
        public IQueryable<T> Pages<T>(IQueryable<T> query, int pageIndex, int pageSize, out int count) where T : class
        {
            if (pageIndex < 1)
            {
                pageIndex = 1;
            }
            if (pageSize < 1)
            {
                pageSize = 10;
            }
            count = query.Count();
            query = query.Skip((pageIndex - 1) * pageSize).Take(pageSize);
            return query;
        }

        /// <summary>
        /// 分頁查詢
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public IQueryable<T> Pages<T>(int pageIndex, int pageSize, out int count) where T : class
        {
            if (pageIndex < 1)
            {
                pageIndex = 1;
            }
            if (pageSize < 1)
            {
                pageSize = 10;
            }
            var query = this.DataContext.Set<T>().AsQueryable();
            count = query.Count();
            query = query.Skip((pageIndex - 1) * pageSize).Take(pageSize);
            return query;
        }
        #endregion

        /// <summary>
        /// 做一次提交
        /// </summary>
        #region Save Changes
        public void Save()
        {
            //todo 需要驗證是否需要釋放
            using (this.DataContext)
            {
                this.DataContext.SaveChanges();
            }
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="save"></param>
        public void Add(object entity, bool save = false)
        {
            this.DataContext.Add(entity);
            if (save)
            {
                this.Save();
            }
        }

        /// <summary>
        /// 更新實體
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="save"></param>
        public void Update(object entity, bool save = false)
        {
            this.DataContext.Update(entity);
            if (save)
            {
                this.Save();
            }
        }
        /// <summary>
        /// 更新2
        /// </summary>
        /// <param name="list"></param>
        /// <param name="save"></param>
        public void Update(IEnumerable<object> list, bool save = false)
        {
            this.DataContext.UpdateRange(list);
            if (save)
            {
                this.Save();
            }
        }
        /// <summary>
        /// 刪除1
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="save"></param>
        public void Delete(object entity, bool save = false)
        {
            this.DataContext.Remove(entity);
            if (save)
            {
                this.Save();
            }
        }
        /// <summary>
        /// 刪除2
        /// </summary>
        /// <param name="list"></param>
        /// <param name="save"></param>
        public void Delete(IEnumerable<object> list, bool save = false)
        {
            this.DataContext.RemoveRange(list);
            if (save)
            {
                this.Save();
            }
        }
        #endregion

        ///// <summary>
        ///// 釋放資源
        ///// </summary>
        //public void Dispose()
        //{
        //    _context.Dispose();
        //}
    }

下面是任務調度中心代碼

/// <summary>
    /// 任務調度中心
    /// </summary>
    public class JobCenter
    {
        /// <summary>
        /// 任務計劃
        /// </summary>
        public static IScheduler scheduler = null;
        public static async Task<IScheduler> GetSchedulerAsync()
        {
            if (scheduler != null)
            {
                return scheduler;
            }
            else
            {
                ISchedulerFactory schedf = new StdSchedulerFactory();
                IScheduler sched = await schedf.GetScheduler();
                return sched;
            }
        }
        /// <summary>
        /// 添加任務計劃//或者進程終止後的開啟
        /// </summary>
        /// <returns></returns>
        public async Task<bool> AddScheduleJobAsync(ScheduleInfo m)
        {
            try
            {
                if (m != null)
                {
                    if (m.StarRunTime == null)
                    {
                        m.StarRunTime = DateTime.Now;
                    }
                    DateTimeOffset starRunTime = DateBuilder.NextGivenSecondDate(m.StarRunTime, 1);
                    if (m.EndRunTime == null)
                    {
                        m.EndRunTime = DateTime.MaxValue.AddDays(-1);
                    }
                    DateTimeOffset endRunTime = DateBuilder.NextGivenSecondDate(m.EndRunTime, 1);
                    scheduler = await GetSchedulerAsync();
                    IJobDetail job = JobBuilder.Create<HttpJob>()
                      .WithIdentity(m.JobName, m.JobGroup)
                      .Build();
                    ICronTrigger trigger = (ICronTrigger)TriggerBuilder.Create()
                                                 .StartAt(starRunTime)
                                                 .EndAt(endRunTime)
                                                 .WithIdentity(m.JobName, m.JobGroup)
                                                 .WithCronSchedule(m.CromExpress)
                                                 .Build();
                    //將信息寫入
                    new ScheduleManage().AddSchedule(m);
                    await scheduler.ScheduleJob(job, trigger);
                    await scheduler.Start();
                    await StopScheduleJobAsync(m.JobGroup, m.JobName);
                    return true;
                }
                return false;
            }
            catch (Exception ex)
            {
                //MyLogger.WriteError(ex, null);
                return false;
            }
        }

        /// <summary>
        /// 暫停指定任務計劃
        /// </summary>
        /// <returns></returns>
        public async Task<string> StopScheduleJobAsync(string jobGroup, string jobName)
        {
            try
            {
                scheduler = await GetSchedulerAsync();
                //使任務暫停
                await scheduler.PauseJob(new JobKey(jobName, jobGroup));
                //更新數據庫
                new ScheduleManage().UpdateScheduleStatus(new ScheduleInfo() { JobName = jobName, JobGroup = jobGroup, RunStatus = (int)JobStatus.已停止 });
                var status = new StatusViewModel()
                {
                    Status = 0,
                    Msg = "暫停任務計劃成功",
                };

                return JsonConvert.SerializeObject(status);
            }
            catch (Exception ex)
            {
                //MyLogger.WriteError(ex, null);
                var status = new StatusViewModel()
                {
                    Status = -1,
                    Msg = "暫停任務計劃失敗",
                };
                return JsonConvert.SerializeObject(status);
            }
        }
        /// <summary>
        /// 恢復指定的任務計劃**恢復的是暫停後的任務計劃,如果是程序奔潰後 或者是進程殺死後的恢復,此方法無效
        /// </summary>
        /// <returns></returns>
        public async Task<string> RunScheduleJobAsync(string jobGroup, string jobName)
        {
            try
            {
                //獲取model
                var sm = new ScheduleManage().GetScheduleModel(new ScheduleInfo() { JobName = jobName, JobGroup = jobGroup });
                await AddScheduleJobAsync(sm);
                sm.RunStatus = (int)JobStatus.已啟用;
                //更新model
                new ScheduleManage().UpdateScheduleStatus(sm);
                scheduler = await GetSchedulerAsync();
                //resumejob 恢復
                await scheduler.ResumeJob(new JobKey(jobName, jobGroup));

                var status = new StatusViewModel()
                {
                    Status = 0,
                    Msg = "開啟任務計劃成功",
                };
                return JsonConvert.SerializeObject(status);
            }
            catch (Exception ex)
            {
                var status = new StatusViewModel()
                {
                    Status = -1,
                    Msg = "開啟任務計劃失敗",
                };
                return JsonConvert.SerializeObject(status);
            }
        }
    }

其他幾個文件的細節代碼我就不再粘貼,詳細代碼會推到github上去,接下來寫一個控制器看看效果!

第四部:項目運行截圖

技術分享圖片

具體詳細的東西,也沒有說的十分清晰,具體的代碼可以到github上去查看,

項目github地址:https://github.com/TopGuo/TB.AspNetCore.Quarzt

如果您認為這篇文章還不錯或者有所收獲,您可以點擊右下角的【推薦】按鈕精神支持,因為這種支持是我繼續寫作,分享的最大動力

歡迎大家關註我都我的微信 公眾號,公眾號漲粉絲人數,就是你們對我的喜愛程度!

技術分享圖片

Asp.Net Core 使用Quartz基於界面畫接口管理做定時任務