如何实现异常挂起的Python脚本自动重启保障业务连续运行
PowerShell环境下Python脚本挂起自动重启落地方案
方案1:PowerShell原生守护(最快落地,零额外依赖)
这个方案不需要重构现有业务代码,仅需要在Python脚本主逻辑里加2行心跳上报,再配一个常驻的PowerShell守护脚本即可,适合快速上线解决当前停机问题。
核心逻辑:
- 为每个Python业务脚本分配独立的心跳文件,要求脚本每完成一轮业务处理/每固定间隔(比如30秒),就更新对应心跳文件的时间戳
- 守护脚本按固定频率轮询两个状态:一是对应Python进程是否存活,二是心跳文件最后更新时间是否超过预设阈值
- 判定进程消失/心跳超时(即挂起)时,先强制终止残留的无响应进程,再重新拉起脚本,所有操作写入本地日志留痕
可直接复用的PowerShell守护脚本示例:
<# 单脚本配置项,多脚本部署时复制整段配置、修改参数即可 #> $config = @{ ScriptName = "file_detect_prod.py" WorkDir = "D:\prod_py_scripts\" PythonPath = "C:\Python310\python.exe" HeartbeatFile= "D:\py_heartbeat\file_detect_lastbeat.txt" HangThreshold= 180 # 超过3分钟无心跳判定为挂起,根据业务实际处理时长调整 LogFile = "D:\py_logs\daemon_running.log" } while ($true) { $currentTime = Get-Date $runProc = Get-Process python -ErrorAction SilentlyContinue | Where-Object { $_.CommandLine -like "*$($config.ScriptName)*" } $needRestart = $false if (-not $runProc) { Add-Content $config.LogFile "[$currentTime] 进程$($config.ScriptName)不存在,触发重启" $needRestart = $true } else { if (Test-Path $config.HeartbeatFile) { $lastBeatTime = (Get-Item $config.HeartbeatFile).LastWriteTime $timeDiff = ($currentTime - $lastBeatTime).TotalSeconds if ($timeDiff -gt $config.HangThreshold) { Add-Content $config.LogFile "[$currentTime] 进程$($config.ScriptName)心跳超时$timeDiff秒,判定挂起,触发重启" Stop-Process -Id $runProc.Id -Force Start-Sleep 2 $needRestart = $true } } else { Add-Content $config.LogFile "[$currentTime] 进程$($config.ScriptName)心跳文件丢失,触发重启" Stop-Process -Id $runProc.Id -Force $needRestart = $true } } if ($needRestart) { Start-Process -FilePath $config.PythonPath -ArgumentList $config.ScriptName -WorkingDirectory $config.WorkDir -WindowStyle Hidden Add-Content $config.LogFile "[$currentTime] 进程$($config.ScriptName)重启完成" } Start-Sleep 60 # 每1分钟巡检一次 }
Python侧需要加的心跳代码,直接塞到主业务循环里就行,不碰核心逻辑:
import time # 心跳路径和守护脚本里的配置保持一致 HEARTBEAT_PATH = r"D:\py_heartbeat\file_detect_lastbeat.txt" # 你的原有主逻辑 while True: # 检测新增文件、处理数据、写MySQL的原有代码 # xxx # 每轮处理完更新心跳 with open(HEARTBEAT_PATH, "w", encoding="utf-8") as f: f.write(str(time.time())) time.sleep(1) # 原有轮询间隔
如果遇到单文件处理耗时较长的场景,可以把心跳更新逻辑拆到单独的守护线程里,固定间隔更新,避免处理大文件时被误判为挂起。
方案2:Python进程自托管(不需要单独维护PowerShell脚本)
如果不想额外跑一个PowerShell守护脚本,可以写一个统一的Python入口,用子进程模式托管业务脚本:
- 入口脚本用
subprocess.Popen拉起业务脚本 - 主进程持续监听子进程状态,同时通过心跳文件/管道通信检测子进程是否响应
- 判定子进程退出/挂起时,杀掉残留子进程后重新拉起
- 可额外配置重启冷却规则:比如10分钟内连续重启超过5次,就停止重启并写错误日志,避免脚本死循环崩溃占满资源
方案3:Windows服务化托管(生产环境长期运行推荐)
如果要覆盖服务器崩溃重启的场景,推荐把脚本封装成Windows系统服务:
- 用服务封装工具把每个Python脚本注册为系统服务,设置启动类型为自动,服务器开机后不需要登录就会自动拉起脚本
- 配置服务失败恢复规则:服务异常退出后自动重启,设置合适的重启延迟
- 搭配前面提到的心跳检测逻辑,补充服务自带的进程存活检测无法识别的假死挂起场景
- 服务运行权限可以单独配置,不需要给运维账号之外的人开服务器登录权限
落地避坑要点
- 绝对不能只靠“进程是否存在”判定脚本正常运行,绝大多数挂起场景下Python进程是存活的,但已经停止处理业务,必须加心跳类的健康度检测
- 挂起判定阈值要根据业务实际耗时设置,比如单文件最大处理时长是4分钟,就把阈值设为6-8分钟,避免正常处理被误杀
- 重启前必须强制结束旧进程,防止多实例同时运行导致重复写MySQL、文件重复处理的问题
- 所有重启、异常操作必须写本地日志,记录触发原因和时间,方便后续回溯脚本挂起的根因,逐步修复业务代码的bug
- 有条件的话可以加简单的告警逻辑,触发重启时给相关对接人发通知,方便及时跟进异常情况
内容的提问来源于stack exchange,提问作者panzers1
相关产品推荐
相关产品推荐

