使用TimerTrigger

时间:2017-05-26 15:34:28

标签: c# azure azure-webjobs azure-webjobssdk

我有一个连续的WebJob,其函数使用TimerTrigger每30秒运行一个进程。函数中的特定调用偶尔会看似随机挂起,导致webjob无限期地等待。当前解决方案注意到服务已停止,然后登录Azure仪表板并手动中止。

请注意,我知道正确的操作方法是确定根本原因并进行修复。相信我,我们正在努力。与此同时,我想治疗症状,并需要帮助。

我试图让WebJob使用Timeout装饰器检测状态,如Azure WebJobs SDK上的这篇文章所述:https://github.com/Azure/azure-webjobs-sdk/issues/590。实施该建议后,我能够看到当有问题的呼叫挂断时,会检测到超时,但 WebJob仍然没有死亡。我在这里做错了什么不会杀死函数以允许后续的调用?

Program.cs的

static void Main()
{
    var config = new JobHostConfiguration();
    config.UseTimers();
    config.FunctionTimeout = new TimeSpan(0, 15, 0);
    var host = new JobHost(config);

    Functions.Initialize();
    host.RunAndBlock();
}

Functions.cs

[Singleton]
[Timeout("00:05:00")]
public async static Task PeriodicProcess([TimerTrigger("00:00:30", RunOnStartup = true)] TimerInfo timer, CancellationToken cancelToken, TextWriter log)
{
    log.WriteLine("-- Processing Begin --");

    List<Emails> cases = GetEmailsAndWhatNot();
    foreach (Email e in Emails)
    {
        try
        {
            ProblematicFunction_SendEmail(e, log);
        }
        catch(Exception e)
        {
            // do stuff
        }
    }
    log.WriteLine("-- Processing End -- ");
}


public static void ProblematicFunction_SendEmail(Email e, TextWriter log)
{
    // send email
}

问题期间的WebJob输出

  

- 处理开始 -

     

00:05:00的超时值超出功能&#39; Functions.PeriodicProcess&#39; (Id:&#39; 0f7438bd-baad-451f-95a6-9461f35bfb2d&#39;)。开始取消。

尽管webjob启动取消,但功能并没有消失。我是否需要监控CancellationToken?我需要在多长时间内传播异步调用?我在这里错过了什么会实际中止这个过程?

1 个答案:

答案 0 :(得分:2)

正如TimerTrigger所述有关TimerTrigger的信息:

Singleton Locks

  

TimerTrigger使用WebJobs SDK的 Singleton 功能,确保在任何给定时间只有单个触发函数实例

计划

  

如果函数执行时间超过计时器间隔,则在当前调用完成后才会触发另一次执行。在当前执行完成后安排下一次执行。

以下是我对此方案的测试,您可以参考它:

  • 使用CancellationToken.None并且永远不会传播取消令牌

    enter image description here

    注意:函数PeriodicProcess将在30秒后超时,但耗时的作业仍在运行,并且在长时间运行的作业完成后,处理结束将打印日志。

  • 宣传取消令牌

    enter image description here

    注意:如果我们传播取消令牌,则会立即取消耗时的工作。

代码段

[Timeout("00:00:30")]
[Singleton]
public async static Task PeriodicProcess([TimerTrigger("00:00:10", RunOnStartup = true)] TimerInfo timer, CancellationToken cancelToken, TextWriter log)
{
    log.WriteLine($"-- [{DateTime.Now.ToString()}] Processing Begin --");

    try
    {
        await longRunningJob(log, cancelToken);
    }
    catch (Exception e)
    {
        // do stuff
    }
    log.WriteLine($"-- [{DateTime.Now.ToString()}] Processing End -- ");
}


private async static Task longRunningJob(TextWriter log, CancellationToken cancelToken)
{
    log.WriteLine($"-- [{DateTime.Now.ToString()}] Begin Time-consuming jobs --");
    await Task.Delay(TimeSpan.FromMinutes(1), cancelToken);
    log.WriteLine($"-- [{DateTime.Now.ToString()}] Complete Time-consuming jobs --");
}