欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

在.NET6中使用配置Quartz.NET定時(shí)任務(wù)并使用IHostedService實(shí)現(xiàn)項(xiàng)目啟動(dòng)自動(dòng)加載任務(wù)

 更新時(shí)間:2024年04月19日 11:49:54   作者:kso、  
Quartz.Net是一個(gè)強(qiáng)大、開源、輕量的作業(yè)調(diào)度框架,在平時(shí)的項(xiàng)目開發(fā)當(dāng)中也會(huì)時(shí)不時(shí)的需要運(yùn)用到定時(shí)調(diào)度方面的功能,這篇文章主要介紹了在.NET6中使用配置Quartz.NET定時(shí)任務(wù)并使用IHostedService實(shí)現(xiàn)項(xiàng)目啟動(dòng)自動(dòng)加載任務(wù),需要的朋友可以參考下

1 簡(jiǎn)介

Quartz.Net是一個(gè)強(qiáng)大、開源、輕量的作業(yè)調(diào)度框架,在平時(shí)的項(xiàng)目開發(fā)當(dāng)中也會(huì)時(shí)不時(shí)的需要運(yùn)用到定時(shí)調(diào)度方面的功能,如果每天需要跑任務(wù)的話,你肯定不會(huì)寫個(gè)while循環(huán),里面進(jìn)行任務(wù)作業(yè)吧,這樣是很耗線程的,很耗資源的。所以就有目前的定時(shí)任務(wù)框架。

2 項(xiàng)目級(jí)配置思路

  • 首先第一步我需要配置quartz,數(shù)據(jù)庫(kù)里面有幾十條的任務(wù),有需要運(yùn)行的,有需要暫停的,在項(xiàng)目進(jìn)行更新或者重啟的時(shí)候需要重新加載我設(shè)置的任務(wù)信息,做好日志。
  • 支持任務(wù)的頁(yè)面配置,如,任務(wù)的管理,增刪改。執(zhí)行按鈕操作
  • 統(tǒng)一的進(jìn)行方法配置,采用調(diào)用api的方式進(jìn)行執(zhí)行任務(wù),我們只需要寫好api就行了,在數(shù)據(jù)庫(kù)配置好url。

3 下載包并在program注入

// 1在api層 下載包  <PackageReference Include="Quartz.AspNetCore" Version="3.5.0" />
//2注入配置
//3 net6中  只有program類,直接在里面Build前面添加以下代碼
builder.Services.AddQuartz(q =>
{
    // base quartz scheduler, job and trigger configuration
});
// ASP.NET Core hosting
builder.Services.AddQuartzServer(options =>
{
    // when shutting down we want jobs to complete gracefully
    options.WaitForJobsToComplete = true;
});

4 任務(wù)的幫助類

第一步增加Corn表達(dá)式的幫助類,用于驗(yàn)證Corn輸入是否合格

using Quartz.Impl.Triggers;
namespace common
{
    public static class QuartzUtil
    {
        /// <summary>
        /// 驗(yàn)證 Cron 表達(dá)式是否有效
        /// </summary>
        /// <param name="cronExpression"></param>
        /// <returns></returns>
        public static bool IsValidExpression(this string cronExpression)
        {
            try
            {
                var trigger = new CronTriggerImpl();
                trigger.CronExpressionString = cronExpression;
                var date = trigger.ComputeFirstFireTimeUtc(null);
                return date != null;
            }
            catch //(Exception e)
            {
                return false;
            }
        }
    }
}

第二步 任務(wù)調(diào)度服務(wù)公共類,主要負(fù)責(zé)任務(wù)的運(yùn)行和暫停(復(fù)制代碼,有一些引用的錯(cuò)誤,先不要管)

using Quartz;
using Quartz.Impl.Matchers;
namespace Common
{
    /// <summary>
    /// 任務(wù)調(diào)度服務(wù)
    /// </summary>
    public class QuartzJobService : ITransientSelfDependency
    {
        private readonly ISchedulerFactory _schedulerFactory;
        private readonly ResultfulApiJobFactory _resultfulApiJobFactory;
        public QuartzJobService(ISchedulerFactory schedulerFactory, ResultfulApiJobFactory resultfulApiJobFactory)
        {
            _schedulerFactory = schedulerFactory;
            _resultfulApiJobFactory = resultfulApiJobFactory;
        }
        /// <summary>
        /// 開始運(yùn)行一個(gè)調(diào)度器
        /// </summary>
        /// <param name="tasks"></param>
        /// <returns></returns>
        public async Task<bool> RunAsync(Z_SyncModules tasks)
        { 
            //1、通過調(diào)度工廠獲得調(diào)度器
            var scheduler = await _schedulerFactory.GetScheduler();
            var taskName = $"{tasks.Id}>{tasks.ModuleName}";
            //2、創(chuàng)建一個(gè)觸發(fā)器
            var trigger = TriggerBuilder.Create()
                .WithIdentity(taskName, taskName)
                .StartNow()
                .WithDescription(tasks.Description)
               // .WithSimpleSchedule(x => x.WithIntervalInSeconds((int)tasks.Frequency).RepeatForever())
                 觸發(fā)表達(dá)式 0 0 0 1 1 ?
                .WithCronSchedule(tasks.SyncTime)
                .Build();
            //3、創(chuàng)建任務(wù)
            var jobDetail = JobBuilder.Create<ResultfulApiJob>()
                            .WithIdentity(taskName, taskName)
                            .UsingJobData("TasksId", tasks.Id.ToString())
                            .Build();
            //4、寫入 Job 實(shí)例工廠 解決 Job 中取 ioc 對(duì)象
            scheduler.JobFactory = _resultfulApiJobFactory;
            //5、將觸發(fā)器和任務(wù)器綁定到調(diào)度器中
            await scheduler.ScheduleJob(jobDetail, trigger);
            //6、開啟調(diào)度器
            await scheduler.Start();
            Console.WriteLine("運(yùn)行成功:" + taskName);
            return await Task.FromResult(true);
        }
        /// <summary>
        /// 關(guān)閉調(diào)度器
        /// </summary>
        /// <param name="tasks"></param>
        /// <returns></returns>
        public async Task<bool> CloseAsync(Z_SyncModules tasks)
        {
            IScheduler scheduler = await _schedulerFactory.GetScheduler();
            var taskName = $"{tasks.Id}>{tasks.ModuleName}";
            var jobKeys = (await scheduler
                .GetJobKeys(GroupMatcher<JobKey>.GroupEquals(taskName)))
                .ToList().FirstOrDefault();
            if (jobKeys == null )
            {
                MessageBox.Show($"未找到任務(wù):{taskName}");
            }
            var triggers = await scheduler.GetTriggersOfJob(jobKeys);
            ITrigger trigger = triggers?.Where(x => x.JobKey.Name == taskName).FirstOrDefault();
            if (trigger == null)
            {
                MessageBox.Show($"未找到觸發(fā)器:{taskName}");
            }
            await scheduler.PauseTrigger(trigger.Key);
            await scheduler.UnscheduleJob(trigger.Key);// 移除觸發(fā)器
            await scheduler.DeleteJob(trigger.JobKey);
            Console.WriteLine("關(guān)閉成功:"+ taskName);
            return await Task.FromResult(true);
        } 
    }
}

第三步 運(yùn)行的方法,也就是任務(wù)運(yùn)行的時(shí)候,需要指定一個(gè)類,繼承 IJob,也就是我們都使用這個(gè)類去執(zhí)行方法

using Quartz;
using System.Diagnostics;
namespace HZY.Quartz.Service.Jobs
{
    /// <summary>
    /// Resultful 風(fēng)格 Api Job
    /// </summary>
    [DisallowConcurrentExecution]
    public class ResultfulApiJob : IJob
    {
        private readonly ApiRequestService _apiRequestService;
        private readonly IServiceProvider _provider;
        private readonly ILogger<ResultfulApiJob> _logger;
        public ResultfulApiJob(ApiRequestService apiRequestService, ILogger<ResultfulApiJob> logger, IServiceProvider provider)
        {
            _apiRequestService = apiRequestService;
            _logger = logger;
            _provider = provider;
        }
        public async Task Execute(IJobExecutionContext context)
        {
            try
            {
                Stopwatch _stopwatch = new Stopwatch();
                _stopwatch.Restart();
                 var tasksId = context.MergedJobDataMap.GetString("TasksId")?.ToString();
                if (string.IsNullOrWhiteSpace(tasksId))
                {
                    _logger.LogError("tasksId 空!");
                    return;
                }
                Z_SyncModules tasks = null;
                using (var scope = _provider.CreateScope())
                {
                    // 解析你的作用域服務(wù)
                    var service = scope.ServiceProvider.GetService<IAdminRepository<Z_SyncModules>>();
                    tasks = await service.SelectNoTracking.FirstOrDefaultAsync(w=>w.Id==Guid.Parse(tasksId));
                }
                if (tasks == null)
                {
                    _logger.LogError("tasks 空!");
                    return;
                }
                var time = DateTime.Now;
                var taskId = tasks?.Id ?? Guid.Empty;
                var text = $"{tasks.ModuleName}|組={tasks.ModuleName}|{time:yyyy-MM-dd}|StartTime={time: HH:mm:ss:fff}|";
                var result = await _apiRequestService.RequestAsync("Post", tasks.ApiUrl);
                if (!result.IsSuccess)
                {
                    _logger.LogError($"Web Api RequestAsync(); 請(qǐng)求失敗! WebApi 返回結(jié)果:{result.Message}");
                }
                _stopwatch.Stop();
                var endTime = $"{DateTime.Now:HH:mm:ss:fff}";
                //運(yùn)行結(jié)束記錄
                text += $"EndTime={endTime}|{_stopwatch.ElapsedMilliseconds} 毫秒|結(jié)果={result.Message}";
            }
            catch (Exception ex)
            {
                var message = $@"Message={ex.Message}\r\n
StackTrace={ex.StackTrace}\r\n
Source={ex.Source}\r\n";
                _logger.LogError(ex, message, null);
            }
        }
    }
}

第四步注入IJob實(shí)例,方便注入

using Quartz;
using Quartz.Spi;
namespace HZY.Services.Admin.QuartzJobTask
{
    /// <summary>
    /// IJob 對(duì)象無(wú)法構(gòu)造注入 需要此類實(shí)現(xiàn) 返回 注入后得 Job 實(shí)例
    /// </summary>
    public class ResultfulApiJobFactory : IJobFactory
    {
        private readonly IServiceProvider _serviceProvider;
        public ResultfulApiJobFactory(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }
        public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
        {
            //Job類型
            Type jobType = bundle.JobDetail.JobType;
            return _serviceProvider.GetService(jobType) as IJob;
        }
        public void ReturnJob(IJob job)
        {
            var disposable = job as IDisposable;
            disposable?.Dispose();
        }
    }
}

第五步就是webapi的請(qǐng)求,也就是那些post,get請(qǐng)求

我這里直接用的開源框架  Flurl.Http 

namespace Common
{
    /// <summary>
    /// WebApi 請(qǐng)求服務(wù)
    /// </summary>
    public class ApiRequestService : ITransientSelfDependency
    {
        private readonly ILogger<ApiRequestService> _logger;
        public ApiRequestService(ILogger<ApiRequestService> logger)
        {
            _logger = logger;
        }
        /// <summary>
        /// 請(qǐng)求數(shù)據(jù)
        /// </summary>
        /// <param name="requsetMode"></param>
        /// <param name="apiUrl"></param>
        /// <param name="headerKeyValue"></param>
        /// <returns></returns>
        public async Task<(bool IsSuccess, string Message)> RequestAsync(string requsetMode, string apiUrl, string headerKeyValue = null)
        {
            try
            {
                var headerKey = "HZY.Quartz.Job.Request";
                var headerValue = "Success";
                if (!string.IsNullOrWhiteSpace(headerKeyValue) && headerKeyValue.Contains("="))
                {
                    headerKey = headerKeyValue.Split('=')[0];
                    headerValue = headerKeyValue.Split('=')[1];
                }
                IFlurlRequest flurlRequest = apiUrl.WithHeader(headerKey, headerValue);
                if (flurlRequest == null)
                {
                    return (false, "flurlRequest 空指針!");
                }
                IFlurlResponse flurResponse = default;
                if (requsetMode == "Post")
                {
                    flurResponse = await flurlRequest.PostAsync();
                }
                if (requsetMode == "Get")
                {
                    flurResponse = await flurlRequest.GetAsync();
                }
                if (flurResponse == null)
                {
                    return (false, "flurResponse 空指針!");
                }
                var result = await flurResponse.GetStringAsync();
                if (string.IsNullOrWhiteSpace(result))
                {
                    return (false, "result 空指針!");
                }
                return (true, result);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"接口請(qǐng)求異?!続piRequestService 》RequestAsync】:{ex.Message}");
                return (false, ex.Message);
            }
        }
    }
}

5 ioc容器注入

  services.AddTransient<ISchedulerFactory, StdSchedulerFactory>();  
        //Job 實(shí)例化工廠
        services.AddSingleton<ResultfulApiJobFactory>();
        //Reultful 風(fēng)格 api 請(qǐng)求 任務(wù)
        services.AddTransient<ResultfulApiJob>();

6 實(shí)現(xiàn)項(xiàng)目啟動(dòng)就從數(shù)據(jù)庫(kù)里面運(yùn)行加載任務(wù)

寫一個(gè) Worker 繼承 IHostedService 
里面的邏輯就寫,讀數(shù)據(jù)庫(kù),循環(huán)加載任務(wù),加載任務(wù)的方法就在上面的RUNAsync()
using System.Threading;
using System.Threading.Tasks;
namespace HZY.Quartz
{
    public class Worker : IHostedService
    {
        private readonly ILogger<Worker> _logger;
        private readonly IServiceProvider _provider;
        private readonly QuartzJobService _quartzJob;
        public Worker(ILogger<Worker> logger, QuartzJobService quartzJob, IServiceProvider provider)
        {
            _logger = logger;
            this._quartzJob = quartzJob;
            _provider = provider;
        }
        public async Task StartAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation($"程序服務(wù)開始 : {DateTime.Now}");
            List<Z_SyncModules> servicelist = new();
            using (var scope = _provider.CreateScope())
            {
                // 解析你的作用域服務(wù)
                var service = scope.ServiceProvider.GetService<xx>();
                if (service != null)
                {
                    servicelist = await service.Where(xx).ToListAsync();
                }
                _logger.LogInformation($"程序服務(wù)查詢定時(shí)任務(wù)列表成功 : {DateTime.Now}");
                foreach (var item in servicelist)
                {
                    //自動(dòng)恢復(fù)任務(wù)機(jī)制a
                    try
                    {
                        var result = await _quartzJob.RunAsync(item);
                        if (result)
                        {
                            _logger.LogInformation($"自動(dòng)開啟任務(wù)成功 [{DateTime.Now}]  ");
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, $"自動(dòng)開啟任務(wù)錯(cuò)誤 [{DateTime.Now}] : {ex.Message}");
                    }
                }
            }
            await StopAsync(cancellationToken); //在項(xiàng)目查詢運(yùn)行的時(shí)候運(yùn)行一次
        }
        public Task StopAsync(CancellationToken cancellationToken)
        {
            return Task.CompletedTask;
        }
    }
}

7 總結(jié)

以上就是我之前在項(xiàng)目中使用定時(shí)任務(wù)的一些邏輯和代碼,
當(dāng)然了我還參照了目前的開源項(xiàng)目 https://gitee.com/hzy6/hzy-quartz 一些設(shè)計(jì)思想和代碼
,基本上在項(xiàng)目中可以隨便使用。具體的一些執(zhí)行邏輯就可以自己去寫

8 Corn

Cron表達(dá)式生成器1:https://fontawesome.com
Cron表達(dá)式生成器2:https://cron.qqe2.com/
0 0/60 * * * ?    每60分鐘執(zhí)行一次
0 55 7 * * ?    每天7:55執(zhí)行一次
0 0 1 ? * L    每周一凌晨1點(diǎn)執(zhí)行
0 0 18 18 * ?    每月18號(hào)18點(diǎn)執(zhí)行一次

到此這篇關(guān)于在.NET6中使用配置Quartz.NET定時(shí)任務(wù)并使用IHostedService實(shí)現(xiàn)項(xiàng)目啟動(dòng)自動(dòng)加載任務(wù)的文章就介紹到這了,更多相關(guān).NET6 Quartz.NET定時(shí)任務(wù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論