使用SIGTERM信号优雅终止程序时数据库断开连接失败的问题求助
SIGTERM信号优雅终止程序时数据库断开连接失败的问题求助
我最近在学习使用信号机制,写了一个连接数据库并查询打印结果的小Demo。程序里我特意让数据库连接保持打开状态,发送SIGTERM信号确实能终止程序,但当我尝试在信号处理函数里添加数据库断开的逻辑时却失败了。我明明已经把db声明为全局变量了,想请教一下各位我哪里操作错了?我的最终目标是实现程序的优雅关闭,清理数据库连接、Socket连接这类资源。
我的代码如下:
import signal import sys from time import sleep global db def term_handler(signum,frame): print('In term handler') db.disconnect() #more clean up to come. sys.exit() def main(): db = connection # 这里的connection是数据库连接对象,比如pymysql.connect之类的实例 results = db.select('query here') print(results.fetchall()) #db.disconnect() # 上面这行在main里调用是正常的,但放到term_handler里就失败 signal.signal(signal.SIGTERM,term_handler) while True: print('yes') sleep(2) return None if __name__ == "__main__": main()
问题分析
核心问题出在全局变量的作用域处理上:
你虽然在term_handler外部声明了global db,但在main函数里直接赋值db = connection时,Python会把这个db当成main函数的局部变量,并没有把值同步到你之前声明的全局db上。当SIGTERM信号触发term_handler时,全局的db其实是未初始化的状态,这时候调用db.disconnect()自然会抛出类似NameError或者属性不存在的错误。
解决方案
最简单的修正方式是在main函数里也明确声明使用全局的db,这样赋值时才会修改全局变量,而不是创建局部变量:
def main(): global db # 声明这里使用全局的db变量 db = connection results = db.select('query here') print(results.fetchall()) signal.signal(signal.SIGTERM,term_handler) while True: print('yes') sleep(2)
额外提示
- 信号处理函数里尽量避免执行复杂的IO操作或者调用非信号安全的库函数,不过数据库的
disconnect一般是安全的,但最好提前测试确认。 - 如果不想用全局变量,也可以考虑用类来封装所有需要清理的资源(比如数据库连接、Socket),然后在信号处理函数里调用类的清理方法,这样代码结构会更清晰。
备注:内容来源于stack exchange,提问作者newdeveloper
相关产品推荐
相关产品推荐

