You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

.NET 5 Web API控制器中手动触发Quartz.NET任务及解决IScheduler依赖注入异常方案

解决Quartz.NET IScheduler注入失败及任务管理问题

1. 修复IScheduler注入异常

你遇到的InvalidOperationException是因为Quartz.NET默认不会把IScheduler直接注册到ASP.NET Core的依赖注入容器里,正确的做法是注入ISchedulerFactory,然后通过它来获取调度器实例。另外注意你原来的控制器中注入的ILogger<WeatherForecastController>是错误的,应该改为ILogger<QuartzController>,避免日志上下文错误。

修改后的QuartzController代码如下:

[ApiController]
[Route("[controller]")]
public class QuartzController : ControllerBase {
    private readonly ISchedulerFactory _schedulerFactory;
    private readonly ILogger<QuartzController> _logger;

    // 注入ISchedulerFactory而非直接IScheduler
    public QuartzController(ISchedulerFactory schedulerFactory, ILogger<QuartzController> logger) {
        _schedulerFactory = schedulerFactory;
        _logger = logger;
    }

    [HttpGet("Run")]
    public async Task<IActionResult> Run(string jobName) {
        // 获取调度器实例
        var scheduler = await _schedulerFactory.GetSchedulerAsync();
        
        // 构建任务Key(注意要和你注册任务时的Key一致)
        var jobKey = new JobKey(jobName);
        
        // 1. 检查任务是否存在
        var jobExists = await scheduler.CheckExistsAsync(jobKey);
        if (!jobExists) {
            _logger.LogWarning("任务 {JobName} 不存在", jobName);
            return NotFound($"任务 {jobName} 不存在");
        }

        // 2. 手动触发任务
        await scheduler.TriggerJobAsync(jobKey);
        _logger.LogInformation("任务 {JobName} 已触发", jobName);

        // 3. 获取任务及触发器相关状态
        var jobDetail = await scheduler.GetJobDetailAsync(jobKey);
        // 获取任务绑定的所有触发器状态
        var triggers = await scheduler.GetTriggersOfJobAsync(jobKey);
        var triggerStates = new Dictionary<string, TriggerState>();
        foreach (var trigger in triggers) {
            var state = await scheduler.GetTriggerStateAsync(trigger.Key);
            triggerStates.Add(trigger.Key.Name, state);
        }
        // 获取当前正在运行的任务(如果需要确认任务是否正在执行)
        var runningJobs = await scheduler.GetCurrentlyExecutingJobsAsync();
        var isJobRunning = runningJobs.Any(j => j.JobDetail.Key.Equals(jobKey));

        var response = new {
            Message = $"任务 {jobName} 已成功触发",
            JobDescription = jobDetail.Description,
            IsJobRunning = isJobRunning,
            TriggerStates = triggerStates
        };

        return Ok(response);
    }
}

2. 确保JobKey与注册时一致

你使用的AddJobAndTrigger方法通常会根据任务类型生成JobKey,默认是用任务类的完整命名空间+类名作为JobKey的Name(比如QuartzTest.HelloWorldJob),而不是简单的HelloWorldJob。如果想自定义JobKey,可以修改注册逻辑,显式指定任务标识:

services.AddQuartz(q => {
    q.UseMicrosoftDependencyInjectionJobFactory();
    // 显式指定JobKey,方便后续调用
    q.AddJob<HelloWorldJob>(job => job.WithIdentity("HelloWorldJob"));
    // 绑定触发器(示例:每5秒执行一次,可根据配置调整)
    q.AddTrigger(trigger => trigger
        .ForJob("HelloWorldJob")
        .WithIdentity("HelloWorldJob-Trigger")
        .WithCronSchedule("0/5 * * * * ?"));
});

3. 关键API说明

  • CheckExistsAsync(jobKey):验证指定JobKey的任务是否已注册到调度器
  • TriggerJobAsync(jobKey):手动触发指定任务,不管其原有触发器配置
  • GetTriggerStateAsync(triggerKey):获取触发器状态(比如Normal正常调度、Paused暂停、Completed已完成等)
  • GetCurrentlyExecutingJobsAsync():获取当前正在运行的所有任务,可用来判断目标任务是否处于执行状态

内容的提问来源于stack exchange,提问作者Misiu

火山引擎 最新活动