7

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

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

在黑暗中,我尝试将以下代码添加到我的 C# 控制台应用程序中:

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

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

因此,我正在寻找一种好方法,让我的 WebJob 被通知它的秒数已编号,并且它需要按顺序处理它的事务。

4

1 回答 1

10

我相信在阿米特最后一次回答之后事情很快就发生了变化,根据他自己的博客文章实际上在这里:WebJobs Graceful Shutdown

还可以在 6:00+ 标记之后查看此视频,以对此进行一些讨论。

来自 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();
                }
            }
        }

    }
}
于 2015-05-08T07:32:36.303 回答