如何让Python程序遇未捕获异常即退出或通过systemctl异常重启服务?
临时解决方案:让Python服务遇未捕获异常即退出,或通过systemctl强制重启
一、Python层面:强制未捕获异常触发进程退出
默认情况下,线程或异步任务中的未捕获异常不会终止主进程,你可以通过设置全局异常钩子,让任何未处理的异常直接强制退出进程,这样Restart=always就能生效。
1. 处理线程中的未捕获异常
将以下代码添加到服务启动入口:
import sys import os import threading def handle_uncaught_exception(exc_type, exc_value, exc_traceback): print(f"未捕获异常: {exc_type.__name__}: {exc_value}", file=sys.stderr) # 用os._exit强制终止整个进程,不会被线程阻塞 os._exit(1) # 覆盖全局异常钩子 sys.excepthook = handle_uncaught_exception # 覆盖线程异常钩子(默认线程异常不会触发全局钩子) def thread_exception_handler(args): handle_uncaught_exception(args.exc_type, args.exc_value, args.exc_traceback) threading.excepthook = thread_exception_handler
2. 处理异步任务中的未捕获异常
如果使用asyncio,可以给所有异步任务加一个包装器,捕获异常后强制退出:
import asyncio async def async_task_wrapper(coro): try: await coro except Exception as e: print(f"异步任务异常: {type(e).__name__}: {e}", file=sys.stderr) os._exit(1) # 启动异步任务时使用该包装器,示例: # asyncio.run(async_task_wrapper(your_async_function()))
二、Systemd层面:用Watchdog监控服务状态
如果不想修改Python代码,可以通过systemd的Watchdog功能,让系统定期检查服务运行状态,一旦心跳中断就重启服务。
1. 修改systemd服务文件
在你的.service文件中添加以下配置:
[Service] # 开启Watchdog,设置30秒超时 WatchdogSec=30s # 服务故障(含Watchdog超时)时重启 Restart=on-failure # 可选:若服务支持notify机制,设置类型 Type=notify
2. 在Python服务中添加心跳发送逻辑
先安装sdnotify库(pip install sdnotify),然后在服务启动后定期发送心跳:
import sdnotify import time import threading # 初始化systemd通知器 notifier = sdnotify.SystemdNotifier() # 告知systemd服务已就绪 notifier.notify("READY=1") # 启动心跳线程,每隔25秒发送一次(需小于WatchdogSec的值) def send_watchdog_heartbeat(): while True: notifier.notify("WATCHDOG=1") time.sleep(25) # 守护线程,随主进程退出而终止 threading.Thread(target=send_watchdog_heartbeat, daemon=True).start()
若服务因异常卡住无法发送心跳,systemd会在30秒后自动重启服务。
内容的提问来源于stack exchange,提问作者Guilherme Richter
相关产品推荐
相关产品推荐

