Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/arduino/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从Quartz.net中运行的作业获取数据_C#_Quartz.net - Fatal编程技术网

C# 从Quartz.net中运行的作业获取数据

C# 从Quartz.net中运行的作业获取数据,c#,quartz.net,C#,Quartz.net,我正在尝试在Quartz.net中创建一个作业,该作业将监视所有其他作业的状态,并定期更新日志文件。它只在作业完成执行后从作业中获取数据,但我正在尝试获取作业状态的动态信息 我写了一个尽可能简单的测试作业,而测试的一半工作正常(这很令人沮丧,因为我不知道实际代码中有什么不同)。这是测试代码: 工作 [PersistJobDataAfterExecution] [DisallowConcurrentExecution] class SimpleFeedbackJob : IInterruptabl

我正在尝试在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()
    {
    }
}
因此,这确实会将一些数据输出到
log.txt
,它获得了正确的上一次运行时间,但它只显示了
“idle”
状态,我认为这应该是
“working”
时间的一半。换句话说,我希望在作业仍在运行时写入并访问作业数据


有没有可能像这样在作业的中途从作业
Execute()
获取数据?

简单的回答是,没有现成的方法可以做到这一点。下面是在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的实现替换为您的实现。内置的JobRunShell有一个对作业执行上下文的引用,因此它能够读取数据映射(可能使用计时器?),然后报告状态。您必须为此创建自己的。以下是默认的jobRunShellFactory实现

  • Quartz.Net在不同的线程上执行作业,因此在作业进行时与它们进行通信与在运行中与任何其他常规线程进行通信时遇到的问题相同。因此,如果您曾经尝试过解决该问题,那么您就知道您面临的是什么。

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

    还有一个小改动:我将
    writeallines
    替换为
    AppendAllLines

    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()
        {
        }
    }
    
    类状态信息
    {
    公共日期时间最后运行;
    公共字符串状态;
    }
    [持久化JobDataAfterExecution]
    [不允许继续执行]
    类SimpleFeedbackJob:IIInterruptableJob
    {
    公共静态状态信息状态信息;
    静态SimpleFeedbackJob()
    {
    设置状态(“空闲”);
    }
    公共空间中断()
    {
    }
    public void Execute(IJobExecutionContext上下文)
    {
    设定状态(“工作”);
    睡眠(5000);
    设置状态(“空闲”);
    }
    私有静态void SetStatus(字符串状态)
    {
    StatusInfo=新的StatusInfo
    {
    LastRun=DateTime。现在,
    状态=状态
    };
    }
    }
    类LogUpdaterJob:IInterruptableJob
    {
    私有字符串\u filepath=@“D:\Temp\Logs\log.txt”;
    public void Execute(IJobExecutionContext上下文)
    {
    列表行=新列表();
    var statusInfo=SimpleFeedbackJob.statusInfo;
    Add(String.Format(“{0,-25}{1,-25}”),
    statusInfo.LastRun,
    statusInfo.Status);
    追加所有行(_filepath,行);
    }
    公共空间中断()
    {
    }
    }
    
    我是Quartz.NET的新手,因此无法直接回答,但。。。也许你可以用另一种方式来解决这个问题?既然您似乎希望所有作业都引发相同的行为(例如,将状态/进度报告到公共日志),那么将所有作业从执行此操作的基类继承是否可行?只是一个想法。。。[希望我能回答悬赏;-)]@InteXX这正是我在此期间所做的(即使我在这里得到了答案,因为时间紧迫,我现在也不太可能再次更改它)-但这意味着每次作业要写入时都要锁定,我不相信我是以100%线程安全的方式完成的。这还意味着我必须等待作业运行,然后才能从中获取特定信息。但不管怎样,肯定有办法从你在Quartz.net的工作中获取实时数据,撇开我的具体问题不谈……到目前为止,我还没有遇到一个没有紧迫时间的项目:)好的,祝你好运。如果我有什么想法,我会告诉你的。这能帮上忙吗?它可能。。。但可能不会。我看不到任何文档,所以我不知道它作为API的功能。但我宁愿登录到每个作业中的文本文件,也不愿尝试找到另一个第三方库。不过谢谢。这看起来很有效。在这种情况下,JobDataMap的意义何在?它的主要目的是允许使用不同的参数集调度同一类型作业的多个实例。如果您想将作业持久化到数据库中,它甚至更方便。例如,如果您的进程没有连续运行,或者您正在运行Quartz群集。在这种情况下,Quartz将负责序列化和数据库处理。请稍候。。。如果我有许多作业继承自
    SimpleFeedbackJob
    ,这仍然有效吗?有没有办法制作
    StatusInfoclass 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()
        {
        }
    }