原始碼地址: https://github.com/246850/Calamus.TaskScheduler
演示地址:http://47.101.47.193:1063/
1、Quartz.NET框架核心類
IScheduler:排程者
IJobDetail:任務
ITrigger:觸發器
JobKey:任務/觸發器標識
JobDataMap:資料包
2、郵件通知(FluentEmail類庫)
_fluentEmail.To(to).Subject(subject).Body(body, true).SendAsync();
3、Quartz.NET宿主方式,依靠IHostedService後臺服務執行
internal class QuartzHostedService : IHostedService { private readonly ISchedulerFactory schedulerFactory; private readonly IOptions<QuartzHostedServiceOptions> options; private IScheduler scheduler = null!; public QuartzHostedService( ISchedulerFactory schedulerFactory, IOptions<QuartzHostedServiceOptions> options) { this.schedulerFactory = schedulerFactory; this.options = options; } public async Task StartAsync(CancellationToken cancellationToken) { scheduler = await schedulerFactory.GetScheduler(cancellationToken); await scheduler.Start(cancellationToken); } public Task StopAsync(CancellationToken cancellationToken) { return scheduler.Shutdown(options.Value.WaitForJobsToComplete, cancellationToken); } }
4.Asp.Net Core 5.0整合
安裝依賴包
Quartz
Quartz.AspNetCore
Quartz.Plugins.TimeZoneConverter
Quartz.Serialization.Json
FluentEmail.Core
FluentEmail.Smtp
Startup
public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(options => { options.Filters.Add<GatewayResultFilterAttribute>(); // 通用執行結果包裝處理過濾器 options.Filters.Add<GlobalExceptionFilterAttribute>(); // 全域性異常過濾器 }) .AddJsonOptions(options => { options.JsonSerializerOptions.Converters.Add(new DateTimeConverter()); // 日期格式化 }) .AddFluentValidation(config => // 請求模型引數驗證 { config.RunDefaultMvcValidationAfterFluentValidationExecutes = true; // false : 禁止預設模型驗證 config.ValidatorOptions.CascadeMode = CascadeMode.Stop; // 不級聯驗證,第一個規則錯誤就停止 config.RegisterValidatorsFromAssemblyContaining<JobCreateOrUpdateValidator>(); }); services.AddHostedService<NLogHostService>(); // NLog 關閉服務 services.AddDistributedMemoryCache(); // 分散式快取介面 services.AddSingleton(HtmlEncoder.Create(UnicodeRanges.All));// 解決中文亂碼 services.AddHttpClient(); // IHttpClientFactory IConfigurationSection quartzConfiguration = Configuration.GetSection("Quartz"); // Quartz配置節點 /***********Quartz.NET*********/ services.AddTransient<HttpJob>(); // 註冊job至容器,必須步驟 services.AddQuartz(config => { config.UseTimeZoneConverter(); // 使用MicrosoftDependencyInjectionJobFactory工廠類從 容器 中建立job例項 config.UseMicrosoftDependencyInjectionJobFactory(options => { options.AllowDefaultConstructor = false; // 禁止使用無參構建函式建立 job options.CreateScope = false; }); config.UseDefaultThreadPool(options => { options.MaxConcurrency = 10; // 最大併發執行執行緒數 }); config.UsePersistentStore(options => { options.UseProperties = false; //options.UseBinarySerializer(); // 二進位制序列化 options.UseJsonSerializer(); // json序列化 options.UseMySql(ado => { ado.ConnectionString = quartzConfiguration["Database"]; ado.TablePrefix = quartzConfiguration["TablePrefix"]; // 預設值 QRTZ_ ado.ConnectionStringName = "Quartz.net"; }); }); // 監聽器 config.AddSchedulerListener<DefaultSchedulerListener>(); config.AddJobListener<DefaultJobListener>(); config.AddTriggerListener<DefaultTriggerListener>(); // 啟動NLog日誌檔案清除job config.ScheduleJob<ClearNLogJob>(trigger => { trigger.WithIdentity(NLogJobKey.NameKey, NLogJobKey.GroupKey).StartNow() .WithCronSchedule("0 0 0 1/3 * ? ", cron => cron.WithMisfireHandlingInstructionFireAndProceed()); // 從每月1日開始,每3天執行一次 }, job => { job.WithIdentity(NLogJobKey.NameKey, NLogJobKey.GroupKey) .StoreDurably(false) // 是否持久化, 無關聯觸發器時是否移除,false:移除 .RequestRecovery() // 重啟後是否恢復任務 .WithDescription("每3天清空NLog日誌檔案"); }); }); // IHostedService宿主啟動 Quartz服務 services.AddSingleton<IHostedService, QuartzHostedService>() services.AddQuartzServer(options => { // when shutting down we want jobs to complete gracefully options.WaitForJobsToComplete = true; // 等待任務執行完,再退出 }); /***********FluentEmail*********/ // 為了將郵件通知配置在job data上, 不使用自帶的service註冊方式 //services.AddFluentEmail(quartzConfiguration["Smtp:UserName"], "Quartz.NET任務排程通知") // .AddRazorRenderer() // .AddSmtpSender(quartzConfiguration["Smtp:Host"], Convert.ToInt32(quartzConfiguration["Smtp:Port"]), quartzConfiguration["Smtp:UserName"], quartzConfiguration["Smtp:Password"]); services.AddTransient<IFluentEmail>(serviceProvider => { IScheduler scheduler = serviceProvider.GetRequiredService<ISchedulerFactory>().GetScheduler().Result; JobKey key = new JobKey(EmailJobKeys.NameKey, EmailJobKeys.GroupKey); if (!scheduler.CheckExists(key).Result) { JobDataMap dataMap = new JobDataMap(); dataMap.Put(EmailJobKeys.Host, "smtp.qq.com"); dataMap.Put(EmailJobKeys.Port, 587); // 465埠一直嘗試不通過,奇怪 dataMap.Put(EmailJobKeys.UserName, "390915549@qq.com"); // 作者qq,歡迎騷擾 dataMap.Put(EmailJobKeys.Password, "cirxjtemuzxycagf"); dataMap.Put(EmailJobKeys.To, string.Empty); // 接收者郵件支援多個,以 ; 隔開 dataMap.Put(EmailJobKeys.NickName, "Quartz.NET任務排程通知"); dataMap.Put(EmailJobKeys.CacheExpiry, 30); // 預設30分鐘內只通知一次 IJobDetail job = JobBuilder.Create<HttpJob>() .StoreDurably(true) .RequestRecovery() .WithDescription("郵件通知配置Job,切勿刪除") .WithIdentity(key) .UsingJobData(dataMap) .Build(); scheduler.AddJob(job, true); // 初始化郵件通知配置 } IJobDetail emailJob = scheduler.GetJobDetail(key).Result; IFluentEmail fluentEmail = new Email(new ReplaceRenderer(), new SmtpSender(new SmtpClient(emailJob.JobDataMap.GetString(EmailJobKeys.Host), emailJob.JobDataMap.GetInt(EmailJobKeys.Port)) { EnableSsl = true, Credentials = new NetworkCredential(emailJob.JobDataMap.GetString(EmailJobKeys.UserName), emailJob.JobDataMap.GetString(EmailJobKeys.Password)) }), emailJob.JobDataMap.GetString(EmailJobKeys.UserName), emailJob.JobDataMap.GetString(EmailJobKeys.NickName)); return fluentEmail; }); IocEngine.Instance.Init(services); // 實在沒辦法才弄個靜態容器獲取service, 監聽器裡無法通過建構函式 注入 ISchedulerFactory, IFluentEmail, 猜測應該是迴圈引用了 }
5、謝謝觀看,拜拜