1、背景描述
最近在重写对数据库的探活,循环不断对所有数据库进行select 1探活,但是发现当数据库出现假死的情况下,整个循环都卡主,连接hang死在假死的数据库,主要是这种异常无法通过connect_timeout超时来触发异常,很难捕捉
2、目前解决办法
目前解决办法是通过装饰器直接对函数进行额外的超时判断,将连接信息放到一个函数中,然后通过装饰器对函数进行额外的超时判断,如果再遇到这种假死问题就可以通过装饰器来抛出异常
装饰器代码
def function_timeout(seconds, err_msg='Function call timed out'):
"""
Timeout decorater.
Restrict function exec in special seconds or throw TimeoutError exception.
"""
def decorated(func):
def _handle_timeout(signum, frame):
raise Exception(err_msg)
def wrapper(*args, **kwargs):
signal.signal(signal.SIGALRM, _handle_timeout)
signal.alarm(seconds)
try:
result = func(*args, **kwargs)
finally:
signal.alarm(0)
return result
return functools.wraps(func)(wrapper)
return decorated
@function_timeout(5)
def connection():
xxx
3、案例展示
1、模拟数据库假死,直接kill -19 pid即可模拟
2、首先不用装饰器,在connect_timeout时间设置5s的情况下,程序hang死,手动终止看时间超过5s
3、在使用装饰器的情况下,在超时配置的超时时间后,会自动抛出调用函数超时的异常用于捕捉
4、此方法问题
目前无法在多线程中使用,水平优先,如果有大神有好的解决办法辛苦分享下,感谢大佬们