发布于2026-07-09 阅读(0)
扫一扫,手机访问
先说一个核心结论:捕获 SIGTERM 后不直接清理资源,而是抛出一个自定义异常,让主执行流接管后续工作——这种做法轻量、可复用,且与 Python 的异常处理机制天然契合。它避免了在信号处理器里写大量业务代码,也绕开了多线程或异步环境下的并发风险。

简单来说,就是利用异常来触发 try/except/finally 或上下文管理器的清理逻辑。这样一来,资源释放集中可控,代码也更干净。
信号处理器(signal.signal 回调)运行在中断上下文,而非常规执行流——它可能打断任意正在运行的代码,包括 print、logging、锁操作甚至 GC。在信号处理器里直接执行文件关闭、数据库提交或网络调用,既不安全也不可控。抛出异常,本质上是一种把控制权交还给主执行路径的手段:在已知且受控的位置(比如主循环顶部或请求处理外层)统一响应退出请求,问题就变得简单多了。
实现起来非常干净:
class ShutdownRequested(Exception): passraise ShutdownRequested()try...except ShutdownRequested: 中,except 块内专注资源释放——关闭连接、保存状态、等待子任务等finally 块或 with 上下文管理器兜底,即使异常穿透了,资源也能释放以下是一个带日志、连接池和主循环的简化模板:
import signal
import time
class ShutdownRequested(Exception):
pass
def handle_shutdown(signum, frame):
raise ShutdownRequested()
signal.signal(signal.SIGTERM, handle_shutdown)
signal.signal(signal.SIGINT, handle_shutdown)
# 模拟资源:数据库连接池、文件句柄
db_pool = ["conn1", "conn2"]
log_file = open("app.log", "a")
try:
print("服务启动,按 Ctrl+C 或 kill 发送 SIGTERM")
while True:
# 模拟处理请求
time.sleep(1)
print("working...")
except ShutdownRequested:
print("收到退出信号,开始清理...")
# 有序释放:先停新任务,再等进行中任务,最后关资源
if db_pool:
print(f"关闭 {len(db_pool)} 个数据库连接")
db_pool.clear()
log_file.write("Service stopped gracefully.\n")
log_file.flush()
finally:
log_file.close()
print("资源已释放,进程退出")
实践中有几个关键点需要格外留意:
threading.Event,而不是依赖异常传播。loop.stop() 或 lifespan 协议,配合 asyncio.create_task() 执行清理协程。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8