繁体   English   中英

从Quartz.net中正在运行的作业中获取数据

[英]Getting data from a running job in Quartz.net

我正在尝试在Quartz.net中创建一个工作,它将监视所有其他工作的状态并定期更新日志文件。 它只会在作业完成执行后从作业中获取数据,但我正在尝试获取作业状态的动态信息。

我写了尽可能简单的测试工作,测试一半工作(这是令人沮丧的,因为我无法分辨实际代码中有什么不同)。 这是测试代码:

工作

[PersistJobDataAfterExecution]
[DisallowConcurrentExecution]
class SimpleFeedbackJob : IInterruptableJob
{
    private DateTime _lastRun;
    public string LastRun { get { return _lastRun.ToString(); } }
    private string _status;

    public void Interrupt()
    {
    }

    public void Execute(IJobExecutionContext context)
    {
        _status = "working";
        _lastRun = DateTime.Now;

        JobDataMap jobData = context.JobDetail.JobDataMap;
        jobData["time"] = LastRun;
        jobData["status"] = _status;

        DateTime n = DateTime.Now.AddSeconds(5);
        while (DateTime.Now < n) { }
        //Thread.Sleep(5000);

        _status = "idle";
        jobData["status"] = _status;
    }
}

public class LogUpdaterJob : IInterruptableJob
{
    private IScheduler _scheduler = TaskManager.Scheduler; //This is the same scheduler that will call this task :/
    private string _filepath = Configs.BasePath + @"Logs\log.txt";

    public void Execute(IJobExecutionContext context)
    {
        Func<string, string> UpdatedLineData
           = name =>
           {
               JobKey jobKey = _scheduler.GetJobKeys(GroupMatcher<JobKey>.GroupContains("test")).Where(k => k.Name == name).First();
               IJobDetail job = _scheduler.GetJobDetail(jobKey);
               ITrigger trigger = _scheduler.GetTriggersOfJob(jobKey).First();

               string status = job.JobDataMap.Get("time") as string;
               string time = job.JobDataMap.Get("status") as string;

               return string.Format("{0,-25} {1,-25}", time, status);
           };

        List<string> lines = new List<string>();
        lines.Add(UpdatedLineData("feedback_test"));
        File.WriteAllLines(_filepath, lines);
    }

    public void Interrupt()
    {
    }
}

来自TaskScheduler相关摘录

private static IScheduler _scheduler = StdSchedulerFactory.GetDefaultScheduler();
public static IScheduler Scheduler { get { return _scheduler; } }

public void Run()
{
    _scheduler.Start();

    IJobDetail feedbackJob = JobBuilder.Create<SimpleFeedbackJob>()
                                       .WithIdentity("feedback_test", "test")
                                       .UsingJobData("time", "")
                                       .UsingJobData("status", "")
                                       .Build();

    ITrigger feedbackTrigger = TriggerBuilder.Create()
                                             .WithIdentity("feedback_test", "test")
                                             .WithSimpleSchedule(x => x.WithIntervalInSeconds(10)
                                                                       .RepeatForever())
                                             .Build();

    IJobDetail loggerJob = JobBuilder.Create<LogUpdaterJob>()
                                     .WithIdentity("LogUpdater", "Admin")
                                     .Build();

    ITrigger loggerTrigger = TriggerBuilder.Create()
                                           .WithIdentity("LogUpdater", "Admin")
                                           .WithSimpleSchedule(x => x.WithIntervalInSeconds(1)
                                                                     .RepeatForever())
                                           .Build();

    _scheduler.ScheduleJob(feedbackJob, feedbackTrigger);
    _scheduler.ScheduleJob(loggerJob, loggerTrigger);
}

所以这会将一些数据输出到log.txt ,它会使最后一次运行时间正确,但它只会显示"idle"状态,我认为它应该是"working"一半时间。 换句话说,我希望在作业仍在运行时写入和访问作业数据。

是否有可能通过作业Execute()中途从作业中获取数据?

在作业完成之前,工作数据更改似乎不可用。 因此,请使用专用数据结构来监视作业状态。 在下面的示例中,我使用一个简单的公共静态属性StatusInfo公开了状态信息,该属性可随时用于日志记录作业。

还有一个小的变化:我已经取代WriteAllLinesAppendAllLines

class StatusInfo
{
    public DateTime LastRun;
    public string Status;
}

[PersistJobDataAfterExecution]
[DisallowConcurrentExecution]
class SimpleFeedbackJob : IInterruptableJob
{
    public static StatusInfo StatusInfo;

    static SimpleFeedbackJob()
    {
        SetStatus("idle");
    }

    public void Interrupt()
    {
    }

    public void Execute(IJobExecutionContext context)
    {
        SetStatus("working");

        Thread.Sleep(5000);

        SetStatus("idle");
    }

    private static void SetStatus(string status)
    {
        StatusInfo = new StatusInfo
            {
                LastRun = DateTime.Now,
                Status = status
            };
    }
}

class LogUpdaterJob : IInterruptableJob
{
    private string _filepath = @"D:\Temp\Logs\log.txt";

    public void Execute(IJobExecutionContext context)
    {
        List<string> lines = new List<string>();
        var statusInfo = SimpleFeedbackJob.StatusInfo;
        lines.Add(String.Format("{0,-25} {1,-25}",
            statusInfo.LastRun,
            statusInfo.Status));
        File.AppendAllLines(_filepath, lines);
    }

    public void Interrupt()
    {
    }
}

简短的回答是没有办法开箱即用。 以下是在Quartz.Net中执行您的工作的一些代码。

// Execute the job
try
{
    if (log.IsDebugEnabled)
    {
        log.Debug("Calling Execute on job " + jobDetail.Key);
    }
    job.Execute(jec);
    endTime = SystemTime.UtcNow();
}
catch (JobExecutionException jee)
{
    endTime = SystemTime.UtcNow();
    jobExEx = jee;
    log.Info(string.Format(CultureInfo.InvariantCulture, "Job {0} threw a JobExecutionException: ", jobDetail.Key), jobExEx);
}
catch (Exception e)
{
    endTime = SystemTime.UtcNow();
    log.Error(string.Format(CultureInfo.InvariantCulture, "Job {0} threw an unhandled Exception: ", jobDetail.Key), e);
    SchedulerException se = new SchedulerException("Job threw an unhandled exception.", e);
    qs.NotifySchedulerListenersError(
    string.Format(CultureInfo.InvariantCulture, "Job ({0} threw an exception.", jec.JobDetail.Key), se);
    jobExEx = new JobExecutionException(se, false);
}

您将看到,一旦调用了execute方法,作业将运行并执行其操作,并且仅在作业执行完毕后返回,因此无法接收更新。 这是在JobRunShell.cs文件中,以防您有兴趣查看完整的上下文。

您可以使用作业侦听器来通知作业何时开始运行,错误输出或完成。 虽然这不会给你提供进展信息。 如果您想跟踪工作进度,您可以:

  1. 使用类似于日志记录模型的内容,您将作业传递给记录器,并将其进度记录到记录器中。 然后您的其他工作可以从此记录器中读取以查找状态。 您必须使此记录器全局可用,因为作业在不同的线程上运行,并且需要处理线程注意事项。
  2. 您可以为您更换JobRunShell的实现。 内置的JobRunShell具有对作业执行上下文的引用,因此它可以读取数据映射(可能使用计时器?),然后报告状态。 你必须为此创建自己的IJobRunShellFactory 这是默认的jobRunShellFactory实现。

Quartz.Net在不同的线程上执行作业,因此在它们正在进行时与它们进行通信时会遇到与在飞行中尝试与任何其他常规线程进行通信时相同的问题。 所以,如果你曾试图解决这个问题,那么你就知道自己面临的是什么。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM