Quartz.Examples.AspNetCore
.NetCore的Web系统,后台主要执行多个触发器任务,前台展示所有触发器信息和正在执行的作业的相关信息,还可以通过访问health-UI来查看目前系统健康状态
-
launchSettings.json
{ "profiles": { "Quartz.Examples.AspNetCore": { "commandName": "Project", // 自动打开浏览器 "launchBrowser": true, // 默认的链接地址 "applicationUrl": "http://localhost:5000", "environmentVariables": { // 开发模式 "ASPNETCORE_ENVIRONMENT": "Development" } } } }
-
appsettings.json
Loggin配置,cron设置,路由设置
-
quartz_jobs.config
触发器和作业的xml配置
-
Startup
-
创建Serilog日志
public Startup(IConfiguration configuration) { Log.Logger = new LoggerConfiguration() // 从默认的日志组件中填充事件信息(使用默认配置) .Enrich.FromLogContext() // 写入到控制器中 .WriteTo.Console() // 创建日志 .CreateLogger(); // 赋值 Configuration = configuration; } public IConfiguration Configuration { get; } // 向容器中添加日志 services.AddLogging(loggingBuilder => { loggingBuilder.ClearProviders(); loggingBuilder.AddSerilog(dispose: true); });
-
OpenTelemetry
通过标准化不同的应用程序和框架如何收集和发出可观察性遥测数据,用于管理观测类的数据。
- 可观察性遥测(分布式跟踪、指标等)的供应商中立规范
- 实现用于检测的公共接口的API
- 应用程序使用SDK为插件作者配置工具和接口以编写导出器
- 使你能够将数据发送到你选择的遥测后端的导出器
OpenTelemetry搭配Zipkin来追踪ASP.NET Core服务之间的WebAPI和gRPC请求,Zipkin官网地址
OpenTelemetry搭配Uber的分布式跟踪系统Jaeger来监视系统
// 添加观测数据工具 services.AddOpenTelemetryTracing(builder => { builder // 启用Quartz.NET作业自动数据收集功能 .AddQuartzInstrumentation() // 使用Zipkin来追踪数据请求 .AddZipkinExporter(o => { o.Endpoint = new Uri("http://localhost:9411/api/v2/spans"); }) // 添加Jaeger监听 .AddJaegerExporter(o => { // these are the defaults o.AgentHost = "localhost"; o.AgentPort = 6831; }); });
-
services.AddRazorPages()
Razor Pages
功能:cshtml视图模板- 身分验证服务
Data Annotation
- 支持Attribute
资料检核及IValidateObject
Cache Tag Helper
AddMvcCore()
核心服务
-
Quartz.NET相关代码
// 配置 services.Configure<QuartzOptions>(options => { // 忽略重复项,默认为false options.Scheduling.IgnoreDuplicates = true; // 替换现有配置信息和数据信息,默认为true options.Scheduling.OverWriteExistingData = true; }); // 添加调度配置 services.AddQuartz(q => { // 唯一表示 q.SchedulerId = "Scheduler-Core"; // 程序关闭时中断作业 q.InterruptJobsOnShutdown = true; // 程序关闭时等待作业关闭 q.InterruptJobsOnShutdownWithWait = true; // 并发作业数,默认是1 q.MaxBatchSize = 5; // -- 一下是默认方法 // 默认使用Microsoft的依赖注入 q.UseMicrosoftDependencyInjectionJobFactory(); // 使用默认的类型加载器 q.UseSimpleTypeLoader(); // 使用默认的内存存储 q.UseInMemoryStore(); // 默认的线程池,最大线程数为10 q.UseDefaultThreadPool(maxConcurrency: 10); // 自动中断长时间运行的作业 q.UseJobAutoInterrupt(options => { // 默认最长时间为5分钟 options.DefaultMaxRunTime = TimeSpan.FromMinutes(5); }); // 使用时间转换器,主要用于不同系统之间的转换 q.UseTimeZoneConverter(); // 添加监听 q.AddSchedulerListener<SampleSchedulerListener>(); q.AddJobListener<SampleJobListener>(GroupMatcher<JobKey>.GroupEquals(jobKey.Group)); q.AddTriggerListener<SampleTriggerListener>(); } // 每次都创建一个不同的ExampleJob实例 (AddTransient) services.AddTransient<ExampleJob>(); // 添加SecondSampleJobListener监听(AddSingleton:单例模式) services.AddSingleton<IJobListener, SecondSampleJobListener>(); services.AddSingleton<ITriggerListener>(serviceProvider => { // 添加SecondSampleTriggerListener触发器 var logger = serviceProvider.GetRequiredService<ILogger<SecondSampleTriggerListener>>(); return new SecondSampleTriggerListener(logger, "Example value"); }); // 将appsettings.json的配置信息映射到SampleOptions的实例中 services.Configure<SampleOptions>(Configuration.GetSection("Sample")); // 增加Quzrtz.NET的配置项 services.AddOptions<QuartzOptions>() .Configure<IOptions<SampleOptions>>((options, dep) => { if (!string.IsNullOrWhiteSpace(dep.Value.CronSchedule)) { var jobKey = new JobKey("options-custom-job", "custom"); options.AddJob<ExampleJob>(j => j.WithIdentity(jobKey)); options.AddTrigger(trigger => trigger .WithIdentity("options-custom-trigger", "custom") .ForJob(jobKey) .WithCronSchedule(dep.Value.CronSchedule)); } }); // 添加Quartz.NET的服务 services.AddQuartzServer(options => { // 当程序关闭时需要等待作业完成 options.WaitForJobsToComplete = true; });
-
AddHealthChecksUI
添加健康检查的页面
-
精简方式,访问/health判断健康状态
/* 健康等级 Healthy 健康 Unhealthy 不良 Degraded 降级 */ public void ConfigureServices(IServiceCollection services){ service.AddHealthchecks(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { //可以通过访问/health链接来查看健康等级 app.MapHealthChecks("/health"); }
-
UI页面-Quartz.NET方式
// appsettings.json中 // 健康检测的配置信息 "HealthChecksUI": { // 可以同时监控多个健康检查API "HealthChecks": [ { "Name": "localhost", "Uri": "/healthz" } ], // 当API的健康状态改变时,向指定Uri发送告警数据 "Webhooks": [] } public void ConfigureServices(IServiceCollection services){ // 添加健康检测页面,并将数据存放到内存中 services .AddHealthChecksUI() .AddInMemoryStorage(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseEndpoints(endpoints => { // 配置路由 endpoints.MapRazorPages(); // 健康检测的url链接 endpoints.MapHealthChecks("healthz", new HealthCheckOptions { Predicate = _ => true, // 返回json格式健康检查数据 ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse }); // 添加健康检测页面到路由中,默认为healthchecks-ui endpoints.MapHealthChecksUI(); }); }
-
-
Configure(IApplicationBuilder app, IWebHostEnvironment env)
配置Http request的管道
- app.UseHsts() 将 HTTP 严格传输安全协议 (HSTS) 标头发送到客户端
- app.UseStaticFiles(); 使用静态资源
- app.UseRouting() 使用路由
-
-
SampleJobListener
监听中添加logger
// 初始化请参见:Startup->1.创建Serilog日志 // 实现JobListenerSupport而非IJobListener public class SampleJobListener : JobListenerSupport { //声明一个logger private readonly ILogger<SampleJobListener> logger; public SampleJobListener(ILogger<SampleJobListener> logger) { //赋值 this.logger = logger; } public override string Name => "Sample Job Listener"; public override Task JobToBeExecuted(IJobExecutionContext context, CancellationToken cancellationToken = default) { // 使用 logger.LogInformation("The job is about to be executed, prepare yourself!"); return Task.CompletedTask; } } // 程序中使用logger的监听 services.AddQuartz(q => // 调用监听类-只给jobkey.Group这个群组的创建此监听 q.AddJobListener<SampleJobListener>(GroupMatcher<JobKey>.GroupEquals(jobKey.Group)); );
-
wwwroot
静态资源文件
通过后台UseStaticFiles()方法引入静态变量
-
Pages部分---Razor页面
-
自动生成部分
// View 加上@符就代表是c#相关代码 @page @model Quartz.Examples.AspNetCore.Pages.Index1Model @{ } // ViewModel namespace Quartz.Examples.AspNetCore.Pages { public class Index1Model : PageModel { // 页面加载时调用 public void OnGet() { } } }
-
Quartz.NET中的Razor
-
View
@page @model IndexModel @{ // Html中的title标签值 ViewData["Title"] = "Home page"; } <div class="text-center"> <h1 class="display-4">Scheduled Triggers</h1> // 调用Control中的Model的Triggers变量 @foreach (var trigger in Model.Triggers) { // 将触发器的群组和名称放到span标签中 <span>@trigger.Group / @trigger.Name</span> <br/> } <br /> <h1 class="display-4">Currently Executing Jobs</h1> @foreach (var job in Model.CurrentlyExecutingJobs) { <span>@job.JobDetail.Key.Group / @job.JobDetail.Key.Name - triggered by @job.Trigger.Key.Group / @job.Trigger.Key.Name</span> <br/> } <br /> <h1 class="display-4">Health Status</h1> <a href="/healthchecks-ui">Open health checks UI</a> </div>
-
ViewModel
public class IndexModel : PageModel { // 引入Logging private readonly ILogger<IndexModel> _logger; // 声明一个调度工厂类 private readonly ISchedulerFactory schedulerFactory; // 在服务启动前需要将需要的类进行配置,配置完成后系统会通过接口类获得单例的相关实现类,如java的spring public IndexModel( ILogger<IndexModel> logger, ISchedulerFactory schedulerFactory) { _logger = logger; this.schedulerFactory = schedulerFactory; } // 只读的集合,赋值为空集合 public IReadOnlyCollection<TriggerKey> Triggers { get; set; } = Array.Empty<TriggerKey>(); public IReadOnlyCollection<IJobExecutionContext> CurrentlyExecutingJobs { get; set; } = Array.Empty<IJobExecutionContext>(); public async Task OnGet() { // 等待获取调取实例 var scheduler = await schedulerFactory.GetScheduler(); //获得所有的触发器 Triggers = await scheduler.GetTriggerKeys(GroupMatcher<TriggerKey>.AnyGroup()); // 获得所有在执行的调度作业上下文 CurrentlyExecutingJobs = await scheduler.GetCurrentlyExecutingJobs(); } }
-
-