You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Quartz Scheduler任务执行状态返回至ASP.NET MVC视图?

在ASP.NET MVC中跟踪Quartz.NET任务执行状态的可行方案

因为ViewBag和Session依赖请求生命周期,无法跨长时间运行的任务传递状态,你可以采用以下几种方案:

1. 持久化存储(支持多服务器场景)

将任务状态存储到数据库、Redis等持久化介质中,视图端通过接口获取状态更新UI。

在任务监听器的JobWasExecuted方法中更新状态:

public async Task JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException, CancellationToken cancellationToken = default)
{
    var jobId = context.JobDetail.Key.Name;
    var status = jobException == null ? "Completed" : "Failed";
    
    // 示例:用EF更新数据库中的任务状态表
    using (var dbContext = new YourDbContext())
    {
        var taskStatus = await dbContext.TaskStatuses
            .FirstOrDefaultAsync(t => t.JobId == jobId, cancellationToken);
        
        if (taskStatus != null)
        {
            taskStatus.Status = status;
            taskStatus.FinishTime = DateTime.UtcNow;
            await dbContext.SaveChangesAsync(cancellationToken);
        }
    }
}

在控制器中提供获取状态的接口:

public JsonResult GetJobStatus(string jobId)
{
    using (var dbContext = new YourDbContext())
    {
        var status = dbContext.TaskStatuses
            .Where(t => t.JobId == jobId)
            .Select(t => t.Status)
            .FirstOrDefault() ?? "Unknown";
        
        return Json(new { Status = status }, JsonRequestBehavior.AllowGet);
    }
}

视图端通过AJAX定时轮询该接口,更新页面元素。

2. 内存缓存+静态线程安全容器(单服务器场景)

适合单服务器部署的项目,用线程安全的容器存储状态,避免并发问题。

先定义静态状态跟踪类:

public static class JobStatusTracker
{
    private static readonly ConcurrentDictionary<string, string> _jobStatuses = new ConcurrentDictionary<string, string>();

    public static void UpdateJobStatus(string jobId, string status)
    {
        _jobStatuses.AddOrUpdate(jobId, status, (key, oldVal) => status);
    }

    public static string GetJobStatus(string jobId)
    {
        _jobStatuses.TryGetValue(jobId, out var status);
        return status ?? "Running";
    }
}

在监听器中更新状态:

public async Task JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException, CancellationToken cancellationToken = default)
{
    var jobId = context.JobDetail.Key.Name;
    var status = jobException == null ? "Completed" : "Failed";
    
    JobStatusTracker.UpdateJobStatus(jobId, status);
    await Task.CompletedTask;
}

控制器接口获取状态:

public JsonResult GetJobStatus(string jobId)
{
    var status = JobStatusTracker.GetJobStatus(jobId);
    return Json(new { Status = status }, JsonRequestBehavior.AllowGet);
}

3. SignalR实时推送(最佳实时体验)

通过SignalR在任务完成时主动向客户端推送状态,无需轮询,实时性更好。

创建SignalR Hub:

public class JobStatusHub : Hub
{
    public async Task SendJobStatusUpdate(string jobId, string status)
    {
        await Clients.All.SendAsync("ReceiveJobStatus", jobId, status);
    }
}

在监听器中注入HubContext并推送状态:

private readonly IHubContext<JobStatusHub> _hubContext;

public YourJobListener(IHubContext<JobStatusHub> hubContext)
{
    _hubContext = hubContext;
}

public async Task JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException, CancellationToken cancellationToken = default)
{
    var jobId = context.JobDetail.Key.Name;
    var status = jobException == null ? "Completed" : "Failed";
    
    await _hubContext.Clients.All.SendAsync("ReceiveJobStatus", jobId, status, cancellationToken);
}

视图端监听推送并更新UI:

<script src="~/lib/signalr/signalr.min.js"></script>
<script>
    const connection = new signalR.HubConnectionBuilder()
        .withUrl("/jobStatusHub")
        .build();

    connection.on("ReceiveJobStatus", (jobId, status) => {
        // 根据任务ID匹配并更新页面状态
        if (jobId === "@Model.JobId") {
            document.getElementById("jobStatusDisplay").textContent = `任务状态:${status}`;
        }
    });

    connection.start().catch(err => console.error(err.toString()));
</script>

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 17:05:18