C# 使用TimerTrigger对连续作业使用Azure WebJob超时
我有一个连续的WebJob,其中有一个函数使用TimerTrigger每30秒运行一个进程。函数中的某个特定调用偶尔挂起,看起来是随机挂起的,这会导致webjob无限期地等待。当前的解决方案是,请注意服务已停止,然后登录Azure仪表板并手动中止它 请注意,我知道正确的做法是找出根本原因并加以解决。相信我,我们正在努力。同时,我想治疗这种症状,需要帮助 我正试图让WebJob使用超时装饰器检测状态,如本文在Azure WebJobs SDK上所述:。实现这个建议后,我可以看到当有问题的调用挂起时,会检测到超时,但是WebJob仍然没有死掉。我在这里做错了什么,不会杀死函数以允许后续调用 Program.cs 函数.csC# 使用TimerTrigger对连续作业使用Azure WebJob超时,c#,azure,azure-webjobs,azure-webjobssdk,C#,Azure,Azure Webjobs,Azure Webjobssdk,我有一个连续的WebJob,其中有一个函数使用TimerTrigger每30秒运行一个进程。函数中的某个特定调用偶尔挂起,看起来是随机挂起的,这会导致webjob无限期地等待。当前的解决方案是,请注意服务已停止,然后登录Azure仪表板并手动中止它 请注意,我知道正确的做法是找出根本原因并加以解决。相信我,我们正在努力。同时,我想治疗这种症状,需要帮助 我正试图让WebJob使用超时装饰器检测状态,如本文在Azure WebJobs SDK上所述:。实现这个建议后,我可以看到当有问题的调用挂起时
[Singleton]
[超时(“00:05:00”)]
公共异步静态任务周期进程([TimerTrigger(“00:00:30”,runnstartup=true)]TimerInfo计时器、CancellationToken cancelToken、TextWriter日志)
{
log.WriteLine(“--Processing Begin--”;
列表案例=GetEmailsAndWhatNot();
foreach(电子邮件中的电子邮件)
{
尝试
{
发送电子邮件(e、日志)的问题功能;
}
捕获(例外e)
{
//做事
}
}
log.WriteLine(“--Processing End--”);
}
公共静态无效问题功能\u发送电子邮件(电子邮件e、TextWriter日志)
{
//发送电子邮件
}
问题期间的WebJob输出
--处理开始--
函数“Functions.PeriodicProcess”(Id:'0f7438bd-baad-451f-95a6-9461f35bfb2d')超出了00:05:00的超时值。开始取消
尽管webjob启动了取消,但该功能并没有消失。我需要监视CancellationToken吗?我需要在多大程度上实现异步调用?我在这里遗漏了什么,实际上会中止这个过程 如TimerTrigger所述:
单例锁
TimerTrigger使用WebJobs SDK的Singleton功能来确保在任何给定时间只有一个触发函数实例在运行
日程安排
如果函数执行时间长于计时器间隔,则在当前调用完成之前不会触发另一次执行。计划在当前执行完成后执行下一次
这是我对该场景的测试,您可以参考它:
- 使用
并且永远不要分发取消令牌 注意:功能CancellationToken.None
将在30秒后超时,但耗时的作业仍在运行,长时间运行的作业完成后,将打印处理结束日志PeriodicProcess
- 分发取消令牌 注意:如果我们分发取消令牌,耗时的作业将立即取消
[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 --");
}
是,您需要监视取消令牌上的
IsCancellationRequested
属性。最好的做法是在有支持的情况下尽可能地向下传播。一旦你实现了这一点,它就会起作用。
[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
}
[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 --");
}