【问题标题】:Quartz.net CancellationTokenQuartz.net CancellationToken
【发布时间】:2018-01-24 17:14:48
【问题描述】:

在我的调度程序中,使用quartz.net v3 实现,我正在尝试测试取消令牌的行为:

....
IScheduler scheduler = await factory.GetScheduler();
....
var tokenSource = new CancellationTokenSource();
CancellationToken ct = tokenSource.Token;
// Start scheduler
await scheduler.Start(ct);
// some sleep 
await Task.Delay(TimeSpan.FromSeconds(60));
// communicate cancellation
tokenSource.Cancel();

我有一个无限运行的测试作业,并在 Execute 方法中检查取消令牌:

public async Task Execute(IJobExecutionContext context)
{
    while (true)
    {
        if (context.CancellationToken.IsCancellationRequested)
        {
            context.CancellationToken.ThrowIfCancellationRequested();
        }
    }
}

我希望当tokenSource.Cancel() 被解雇时,作业将进入if 并引发异常。但它不起作用。

【问题讨论】:

    标签: c# .net quartz-scheduler scheduler quartz.net


    【解决方案1】:

    根据documentation,您应该使用Interrupt方法取消Quartz作业。

    NameValueCollection props = new NameValueCollection
    {
        { "quartz.serializer.type", "binary" }
    };
    StdSchedulerFactory factory = new StdSchedulerFactory(props);
    var scheduler = await factory.GetScheduler();
    await scheduler.Start();
    IJobDetail job = JobBuilder.Create<HelloJob>()
        .WithIdentity("myJob", "group1")
        .Build();
    ITrigger trigger = TriggerBuilder.Create()
        .WithIdentity("myTrigger", "group1")
        .StartNow()
        .WithSimpleSchedule(x => x
            .WithRepeatCount(1)
            .WithIntervalInSeconds(40))
        .Build();
    await scheduler.ScheduleJob(job, trigger);
    //Configure the cancellation of the schedule job with jobkey
    await Task.Delay(TimeSpan.FromSeconds(1));
    await scheduler.Interrupt(job.Key);
    

    预定的作业类;

    public class HelloJob : IJob
    {
        public async Task Execute(IJobExecutionContext context)
        {
            while (true)
            {
                if (context.CancellationToken.IsCancellationRequested)
                {
                    context.CancellationToken.ThrowIfCancellationRequested(); 
                    // After interrupt the job, the cancellation request activated
                }
            }
        }
    }
    

    在作业执行后应用scheduler.Interrupt,石英将终止作业。

    编辑

    根据source code(第2151 行),Interrupt 方法应用作业执行上下文的取消标记。所以,最好使用图书馆的设施。

    【讨论】:

    • 好吧,话虽如此,调度器的Start()和Shutdown()方法的参数中的CancellationToken有什么意义呢?我无法理解...
    • 我找不到任何关于它的文档。
    • 无论如何,我已经用你的代码实现了一个例子。它似乎不起作用。事实上,如果你在tokenSource.Cancel() 后面加上await Task.Delay(TimeSpan.FromSeconds(n)),作业仍然会运行到 n 秒结束。
    • 这行得通。但我仍然不明白如何在方法参数中使用CancellationToken。现在即使在.Interrupt()
    • @luke88 - 延迟响应,但也许如果有人也遇到这个线程 - Start、Interrupt 和其他 Quartz 方法中的 CancellationToken 将取消该特定操作 - 例如取消启动调度程序或取消中断作业。这在使用 Ado 作业存储并且数据库连接出现问题并且它只是在等待和等待时很方便,但是您需要正常关闭您的应用程序,这里是取消令牌 - 您可以取消该操作并继续关闭您的应用程序.
    【解决方案2】:

    这是来自 Github Repo 的单元测试:https://github.com/quartznet/quartznet/blob/master/src/Quartz.Tests.Unit/InterrubtableJobTest.cs

    我尝试以相同的方式实现取消,但它也对我不起作用。

    @Stormcloak 我必须检查取消请求,因为我想为该作业执行一些中止操作,例如将状态数据写入数据库。

    编辑:

    因此,经过多次测试和实施。我已经开始运行了。

    这里有一些伪代码:

        this.scheduler = await StdSchedulerFactory.GetDefaultScheduler();
        this.tokenSource = new CancellationTokenSource();
        this.token = tokenSource.Token;
        // Start scheduler.
        await this.scheduler.Start(token);
        // add some jobs here
        // ...
        // cancel running jobs.
        IReadOnlyCollection<IJobExecutionContext> jobs = await this.scheduler.GetCurrentlyExecutingJobs();
        foreach (IJobExecutionContext context in jobs)
        {
           result = await this.scheduler.Interrupt(context.JobDetail.Key, this.token);
        }
        await this.scheduler.Shutdown(true);
    

    所以现在您可以在 Execute 方法中使用 CancellationToken。

    【讨论】:

    • 就像我在@Stormcloak 的答案的评论中所说的那样,我不明白的是如何在.Interrupt 方法中使用CancellationToken 参数。因为似乎如果你将它传递给方法,结果仍然是一样的。
    猜你喜欢
    • 2018-06-06
    • 2023-03-31
    • 1970-01-01
    • 2022-06-17
    • 1970-01-01
    • 1970-01-01
    • 2021-02-18
    • 2013-09-21
    • 2016-04-04
    相关资源
    最近更新 更多