第一步:安装Nuget包
分别安装Quartz、Quartz.AspNetCore、Quartz.Extensions.DependencyInjection
第二步:程序入口配置
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
//读取配置和初始化Log
builder.Services.AddSingleton(new ConfigHelper(builder.Configuration));
builder.Services.AddSingleton(new LogHelper());
CustomParameter.CAPConnectionString = ConfigHelper.GetConnectionString("CAP_Master");
//API配置
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
//Job相关配置
builder.Services.AddQuartz(q =>
{
q.UseMicrosoftDependencyInjectionScopedJobFactory();
});
builder.Services.AddQuartzHostedService(q => q.WaitForJobsToComplete = true);
builder.Services.AddTransient<SampleJob>();
builder.Services.AddSingleton<ISchedulerFactory, StdSchedulerFactory>();
builder.Services.AddSingleton<IJobFactory, SingletonJobFactory>();
builder.Services.AddSingleton<QuartzSchedulerService>();
//HttpClient
builder.Services.AddHttpClient();
builder.Services.AddTransient<HttpClientHelper>();
CustomParameter.CAPConnectionString = ConfigHelper.Get("ConnectionStrings:CAP_Master");
//允许跨域访问
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "MyPolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
}
app.UseCors("MyPolicy"); // 应用CORS策略
app.UseSwagger();
app.UseSwaggerUI();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
}
}
第三步:配置Service
配置QuartzSchedulerService
public class QuartzSchedulerService
{
private readonly ISchedulerFactory _schedulerFactory;
private IScheduler? _scheduler;
private readonly IServiceProvider _serviceProvider;
private const string JOB_GROUP_NAME = "SyncSiteAndUserJobGroup";
private const string JOB_TRIGGER = "SyncSiteAndUserJobTrigger";
public QuartzSchedulerService(ISchedulerFactory schedulerFactory, IServiceProvider serviceProvider)
{
_schedulerFactory = schedulerFactory;
_serviceProvider = serviceProvider;
InitializeScheduler().GetAwaiter().GetResult();
}
private async Task InitializeScheduler()
{
_scheduler = await _schedulerFactory.GetScheduler();
_scheduler.JobFactory = new SingletonJobFactory(_serviceProvider); // 设置DI容器来解析Job的依赖
if (_scheduler != null && !_scheduler.IsStarted)
{
await _scheduler.Start(); // 启动调度器
}
}
/// <summary>
/// Job启动
/// </summary>
/// <returns></returns>
public async Task<ReturnBase> Start()
{
ReturnBase rb = new ReturnBase();
try
{
SampleJob.IsStopTask = false;
//获取任务设定
MicroCAP_ScheduledTask task = ConfigManage.GetScheduledTaskModel();
//改用使用DI容器创建Job
var job = JobBuilder.Create<SampleJob>()
.WithIdentity(task.TaskID, JOB_GROUP_NAME)
.Build();
//开始后立即执行的触发器
var triggerNow = TriggerBuilder.Create()
.WithIdentity(task.TaskID + "Now", JOB_TRIGGER)
.StartNow()
.Build();
//开始后按配置时间执行的触发器
var triggerCron = TriggerBuilder.Create()
.WithIdentity(task.TaskID + "Cron", JOB_TRIGGER)
.WithCronSchedule(task.SyncTime)
.Build();
if (_scheduler != null)
{
await _scheduler.ScheduleJob(job, new HashSet<ITrigger>() { triggerNow, triggerCron }, true);
}
return rb.Ok();
}
catch (Exception ex)
{
LogHelper.Error("Job启动异常:" + ex.ToString());
return rb.Error(500, "Job启动异常:" + ex.Message);
}
}
/// <summary>
/// 停止Job执行
/// </summary>
/// <returns></returns>
public async Task<ReturnBase> Stop()
{
ReturnBase rb = new ReturnBase();
try
{
if (_scheduler != null)
{
//获取任务设定
MicroCAP_ScheduledTask task = ConfigManage.GetScheduledTaskModel();
//获取JobKey
JobKey jobKey = new JobKey(task.TaskID, JOB_GROUP_NAME); //使用之前设定的组名
//删除Job
if (await _scheduler.CheckExists(jobKey))
{
await _scheduler.DeleteJob(jobKey);
}
SampleJob.IsStopTask = true;
return rb.Ok();
}
else
{
return rb.Error(0, "任务调度服务已停止");
}
}
catch (Exception ex)
{
LogHelper.Error("Job停止异常:" + ex.ToString());
return rb.Error(500, "Job停止异常:" + ex.Message);
}
}
/// <summary>
/// 获取Job执行状态
/// </summary>
/// <returns></returns>
public async Task<ReturnBase> GetJobStatus()
{
ReturnBase rb = new ReturnBase();
try
{
if (_scheduler != null)
{
MicroCAP_ScheduledTask task = ConfigManage.GetScheduledTaskModel();
TriggerKey triggerKey = new TriggerKey(task.TaskID + "Now", JOB_TRIGGER);
TriggerState state = await _scheduler.GetTriggerState(triggerKey);
//LogHelper.Info(task.TaskID + "Now - " + state.ToString());
//如果Now不存在,则查找Cron
if (state == TriggerState.Normal || state == TriggerState.Blocked)
{
return rb.Ok(null, "running");
}
else
{
if (state == TriggerState.None || state == TriggerState.Complete)
{
TriggerKey triggerKeyCron = new TriggerKey(task.TaskID + "Cron", JOB_TRIGGER);
TriggerState stateCron = await _scheduler.GetTriggerState(triggerKeyCron);
//LogHelper.Info(task.TaskID + "Cron - " + stateCron.ToString());
if (stateCron == TriggerState.Normal || stateCron == TriggerState.Complete || stateCron == TriggerState.Blocked)
{
return rb.Ok(null, "running");
}
else
{
return rb.Ok(null, "stopped");
}
}
else
{
return rb.Ok(null, "stopped");
}
}
}
return rb.Ok(null, "stopped");
}
catch (Exception ex)
{
LogHelper.Error("获取任务状态异常:" + ex.ToString());
return rb.Error(500, "获取任务状态异常" + ex.Message);
}
}
}
配置SingletonJobFactory
public class SingletonJobFactory : IJobFactory
{
private readonly IServiceProvider _serviceProvider;
public SingletonJobFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
return _serviceProvider.GetRequiredService(bundle.JobDetail.JobType) as IJob;
}
public void ReturnJob(IJob job)
{
// 这里可以添加释放作业的逻辑(如果需要)
(job as IDisposable)?.Dispose();
}
}
第四步:创建Job执行的逻辑
//DisallowConcurrentExecution 可限制单线程执行
[DisallowConcurrentExecution]
public class SampleJob : IJob
{
private readonly HttpClientHelper _httpclient;
public static bool IsStopTask = false;
private readonly IWebHostEnvironment _env;
public SampleJob(HttpClientHelper httpClientHelper, IWebHostEnvironment env)
{
_httpclient = httpClientHelper;
_env = env;
}
public Task Execute(IJobExecutionContext context)
{
//这里创建Job执行逻辑
//获取程式根目录(读取文件使用)
var rootPath = _env.ContentRootPath;
//_httpclient 访问API
return Task.CompletedTask;
}
/// <summary>
///
/// </summary>
private void SendMail(SyncJobReport rp)
{
//省略...
}
/// <summary>
/// 强行中止任务,抛出自定义异常
/// </summary>
/// <exception cref="OperationCanceledException"></exception>
public void Discontinue()
{
if (IsStopTask) throw new OperationCanceledException();
}
}
第五步:创建APIController
[Route("api/[controller]/[action]")]
[ApiController]
public class SchedulerController : ControllerBase
{
private readonly QuartzSchedulerService _schedulerService;
public SchedulerController(QuartzSchedulerService schedulerService)
{
_schedulerService = schedulerService;
}
[HttpPost("start")]
public async Task<IActionResult> Start()
{
return Ok(await _schedulerService.Start());
}
[HttpPost("stop")]
public async Task<IActionResult> Stop()
{
return Ok(await _schedulerService.Stop());
}
[HttpGet("status")]
public async Task<IActionResult> Status()
{
return Ok(await _schedulerService.GetJobStatus());
}
}