Azure WebJobs的优雅关闭

时间:2014-03-15 21:10:34

标签: azure-webjobs

我计划使用连续的Azure WebJob来发送电子邮件和推送通知。我知道WebJobs会因各种原因不时启动和停止。没关系,但我希望有机会清理"在工作关闭之前。

这样我的WebJob就可以更新数据库记录的状态或删除每个批处理中已经处理过的队列项,这样下次作业运行时就不会发送重复的消息。

作为一个黑暗的镜头,我尝试将以下代码添加到我的C#控制台应用程序:

Console.CancelKeyPress += (object sender, ConsoleCancelEventArgs e) =>
{
  e.Cancel = true;
  program.keepRunning = false;
};

然后我使用keepRunning bool来控制main while循环,并在while循环之外放置一个Console.Writeline(" Exited Gracefully")。但这似乎没有帮助。当我告诉作业停止时(使用我的Azure网站的Webjobs选项卡中的停止按钮),作业将从列表中消失,并显示"无法停止作业:' JobName'。& #34;在Azure门户中(位于页面底部)。我没有看到"退出优雅" WebJob日志中的文本。所以我把那些代码拿出来,因为它没有帮助。

所以,我正在寻找一种好方法,让我的WebJob被告知其秒数已编号,并且需要按顺序查看其事务。

1 个答案:

答案 0 :(得分:7)

我相信Amit在最后一次回答之后很快就会发生变化,事实上根据他自己的博客帖子:WebJobs Graceful Shutdown

在6:00+标记之后稍微see this video进行一些讨论。

来自Amit的博客:

  

Azure通知它即将停止的进程的方式是   将文件放置(创建)在作为环境传递的路径中   变量名为WEBJOBS_SHUTDOWN_FILE。

     

任何想要收听关机通知的WebJob都会   实际上必须检查文件的存在(使用简单   File.Exists函数或在任何脚本中使用FileSystemWatcher   你使用的语言),当它显示WebJob需要启动时   清理并打破它的当前循环,最好是它会退出   正确,Azure将继续关闭(站点)过程。

嗯,这听起来不是很有趣。虽然Amit和其他人发布了一些代码来处理这个问题(见帖子),但我发现它仍然比我想要的更笨拙(我更喜欢丑陋的细节在代码中处理一次,然后立即依赖并忘记)。我希望以下是一个更好的改进。我真的想要关闭设置的单行通知,这就是我们现在拥有的以下内容。我刚刚测试了这个解决方案,关闭了我的工作并正确解雇了它。

所有工作都放在一个单独的文件/类型中,我将其命名为WebJobShutdownNotifier。首先,用法:只需在Main方法中实例化此类型,并传递一个具有关闭工作的void函数(或lamda)。而已!它将触发你的Shutdown方法,而不是说它。我建议WebJobs团队直接在JobHost中加入这个或类似的东西。只需提供订阅活动。

使用示例:

    public static void Main() // your Main method...
    {
        // nice! a single line to handle the shutdown notification, firing your IsShuttingDown method
        var shutdownNotifier = new WebJobShutdownNotifier(IsShuttingDown);

        var host1 = new JobHost();
        host1.RunAndBlock();
    }

    public static void IsShuttingDown()
    {
        Console.WriteLine("Were shutin' down the webjob hatches baby! - {0}", DateTime.UtcNow);
        // do something else here if needed...
    }

// --- WebJobShutdownNotifier.cs ---

using System;
using System.IO;

namespace Microsoft.Azure.WebJobs.Helper
{
    /// <summary>
    /// Base info and code adapted and expanded from Amit Apple:
    /// http://blog.amitapple.com/post/2014/05/webjobs-graceful-shutdown/.
    /// To change the wait on shutdown time from the default of 5 seconds:
    /// "create a file called settings.job with the following content: { "stopping_wait_time": 60 }""
    /// (Nicholas Petersen)
    /// </summary>
    public class WebJobShutdownNotifier
    {
        public bool IsRunning { get; private set; }

        public string ShutdownFilePath { get; private set; }

        public bool FileEnvironmentVariableExisted { get; private set; }

        /// <summary>
        /// Set this as an action allowing you to be notified when it fires that 
        /// shutdown has been triggered (/detected).
        /// </summary>
        public Action IsShuttingDownNotifier { get; set; }

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="isShuttingDownNotifier">
        /// Set this as an action allowing you to be notified when it fires that 
        /// shutdown has been triggered (/detected).
        /// </param>
        public WebJobShutdownNotifier(Action isShuttingDownNotifier = null, bool exceptionIfNoFileEnvironmentVariable = false)
        {
            IsRunning = true;
            IsShuttingDownNotifier = isShuttingDownNotifier;

            // Get the shutdown file path from the environment
            ShutdownFilePath = Environment.GetEnvironmentVariable("WEBJOBS_SHUTDOWN_FILE");

            FileEnvironmentVariableExisted = !string.IsNullOrEmpty(ShutdownFilePath);

            if (!FileEnvironmentVariableExisted) {
                if (exceptionIfNoFileEnvironmentVariable)
                    throw new Exception("WEBJOBS_SHUTDOWN_FILE Environment variable returned null or empty.");
            }
            else {
                // Setup a file system watcher on that file's directory to know when the file is created
                var fileSystemWatcher = new FileSystemWatcher(Path.GetDirectoryName(ShutdownFilePath));
                fileSystemWatcher.Created += OnChanged;
                fileSystemWatcher.Changed += OnChanged;
                fileSystemWatcher.NotifyFilter = NotifyFilters.CreationTime | NotifyFilters.FileName | NotifyFilters.LastWrite;
                fileSystemWatcher.IncludeSubdirectories = false;
                fileSystemWatcher.EnableRaisingEvents = true;
            }
        }

        private void OnChanged(object sender, FileSystemEventArgs e)
        {
            if (IsRunning) { // this was hitting more than once in the short shut down time, do not want to fire IsShuttingDownNotifier more than once...
                if (e.FullPath.IndexOf(Path.GetFileName(ShutdownFilePath), StringComparison.OrdinalIgnoreCase) >= 0) {
                    // Found the file mark, this WebJob has finished
                    IsRunning = false;
                    if (IsShuttingDownNotifier != null)
                        IsShuttingDownNotifier();
                }
            }
        }

    }
}