You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

排查Azure连续WebJobs自动重启及相关代码异常问题

排查Azure连续WebJob自动重启问题并解决死锁困境

首先,咱们先聚焦最核心的问题:查明WebJob自动重启的原因,再逐步解决重启后作业互相等待的死锁问题,以及你之前遇到的FileSystemWatcher初始化错误。

一、排查WebJob自动重启的原因

从你的描述来看,重启发生在夜间且无手动部署操作,CPU内存使用率也始终低于40%,可以从以下几个方向深入排查:

1. 查看Azure平台级日志与通知

  • 实时查看Log Stream:在Azure门户进入你的App Service → MonitoringLog Stream,能实时获取平台层面的重启触发信息,比如应用池回收、主机维护通知等。
  • 开启Diagnostic Settings:将App Service日志发送到Log Analytics,方便回溯历史重启事件,日志里会明确标注重启的触发源(如资源限制、平台维护)。
  • 检查资源健康与通知:在App Service的Overview页面顶部查看Notification区域,Azure会提前通知底层主机维护;同时在Resource Health里可以查看最近的服务中断或重启记录。
  • 通过Kudu站点深挖:访问https://<你的应用名>.scm.azurewebsites.net,进入Process Explorer查看应用池回收历史;也可以在Debug console里打开D:\home\LogFiles\WebJobs\Continuous\<你的WebJob名>目录,里面的系统日志可能包含重启前的关键细节。

2. 排查应用池回收配置

Azure App Service默认的应用池规则可能触发夜间重启:

  • 进入App Service → ConfigurationGeneral settings,检查Idle timeout(空闲超时)和Regular time interval(固定时间回收)。如果设置了较短的空闲超时(比如默认20分钟),夜间无用户请求时可能触发回收,你可以根据业务需求调大或禁用空闲超时。
  • 另外,即使总内存使用率不高,应用池也可能因私有内存限制触发回收,可在Kudu的Process Explorer查看w3wp.exe的私有内存使用情况。

3. 开启WebJob详细诊断日志

在App Service的ConfigurationApplication settings里添加以下配置,获取更精细的WebJob运行日志:

  • 设置WEBJOBS_DIAGNOSTICS_LOG_LEVELVerbose
  • 设置WEBJOBS_LOGS_MAX_SIZE_IN_BYTES10485760(10MB)或更大值

这些日志能帮你捕捉到重启前的异常信号或系统通知。

二、修复FileSystemWatcher初始化错误

你后来修改的代码方向完全正确!之前的错误是把文件名传给了FileSystemWatcher的构造函数,而它需要的是目录路径。这里给你补充一些优化细节:

// 获取关机文件路径
_shutdownFile = Environment.GetEnvironmentVariable("WEBJOBS_SHUTDOWN_FILE");
if (string.IsNullOrEmpty(_shutdownFile))
{
    _log.Info("未检测到WEBJOBS_SHUTDOWN_FILE环境变量,跳过关机监听(本地调试时可能出现此情况)");
    return;
}

_log.Info("监听关机文件:" + _shutdownFile);
var folder = Path.GetDirectoryName(_shutdownFile);
var fileName = Path.GetFileName(_shutdownFile);

if (folder != null && !string.IsNullOrEmpty(fileName))
{
    // 直接指定目录和文件名过滤,避免后续事件判断
    var fileSystemWatcher = new FileSystemWatcher(folder, fileName);
    fileSystemWatcher.Created += OnAzureRestart;
    fileSystemWatcher.Changed += OnAzureRestart;
    fileSystemWatcher.NotifyFilter = NotifyFilters.CreationTime | NotifyFilters.FileName | NotifyFilters.LastWrite;
    fileSystemWatcher.IncludeSubdirectories = false;
    fileSystemWatcher.EnableRaisingEvents = true;
    _log.Info("关机文件监听已设置完成");
}

// 关机事件处理方法
private void OnAzureRestart(object sender, FileSystemEventArgs e)
{
    _log.Info($"检测到关机信号:{e.FullPath}");
    // 核心操作:更新运行作业表,释放当前处理的用户锁
    ReleaseCurrentUserLock();
    _log.Info("优雅关机清理完成,即将退出");
    Environment.Exit(0);
}

三、解决重启后作业互相等待的死锁问题

即使找到了重启原因,也要做好异常重启的兜底方案,建议给运行作业表添加心跳与超时机制

  1. 改造运行作业表结构:新增LastHeartbeat(DateTime类型)字段,记录作业的最后活跃时间。
  2. 优化作业处理逻辑
    • 当作业要处理某个用户的文件时,先查询运行作业表:
      • 若该用户无锁记录,插入新记录(包含作业ID、userId、当前时间作为LastHeartbeat)。
      • 若已有锁记录,检查LastHeartbeat是否超过超时时间(比如10分钟):
        • 超时则判定原作业已异常终止,更新记录为当前作业ID和最新心跳。
        • 未超时则跳过该用户的文件,等待下一轮检查。
    • 文件处理过程中,定期(比如每5分钟)更新LastHeartbeat为当前时间。
  3. 优雅关机时主动清理:在OnAzureRestart方法里,主动将当前处理的用户锁标记为已释放,或直接删除对应记录。

这个机制能确保即使作业异常重启,锁也会在超时后自动释放,彻底避免死锁。

总结

  1. 先通过Azure平台日志、Kudu站点定位重启的根本原因(大概率是应用池回收或平台维护)。
  2. 完善优雅关机逻辑,确保重启时及时释放用户锁。
  3. 添加锁的心跳与超时机制,作为异常重启后的兜底保障。

内容的提问来源于stack exchange,提问作者Paul Meems

火山引擎 最新活动