每次 IO 操作之前或期间都会检查文件可用性,并在文件不可用时优雅处理
This commit is contained in:
@@ -13,16 +13,18 @@ try:
|
|||||||
from eventlet.hubs import hub
|
from eventlet.hubs import hub
|
||||||
from eventlet import hubs
|
from eventlet import hubs
|
||||||
|
|
||||||
# 保存原始的 handle_error 方法
|
# 保存原始的方法
|
||||||
original_handle_error = hub.Hub.handle_error
|
original_handle_error = hub.Hub.handle_error
|
||||||
original_switch = hubs.hub.Hub.switch
|
original_switch = hubs.hub.Hub.switch
|
||||||
|
original_fire_timers = hubs.hub.Hub.fire_timers
|
||||||
|
|
||||||
def custom_handle_error(self, context, type, value, tb):
|
def custom_handle_error(self, context, type, value, tb):
|
||||||
# 忽略 IOClosed 错误和相关的 EOFError
|
# 忽略 IOClosed 错误和相关的 EOFError
|
||||||
error_str = str(value)
|
error_str = str(value)
|
||||||
if (type.__name__ == 'IOClosed' and 'Operation on closed file' in error_str) or \
|
if (type.__name__ == 'IOClosed' and 'Operation on closed file' in error_str) or \
|
||||||
(type.__name__ == 'EOFError') or \
|
(type.__name__ == 'EOFError') or \
|
||||||
(type.__name__ == 'OSError' and 'Bad file descriptor' in error_str):
|
(type.__name__ == 'OSError' and 'Bad file descriptor' in error_str) or \
|
||||||
|
(type.__name__ == 'OSError' and 'Socket operation on non-socket' in error_str):
|
||||||
return
|
return
|
||||||
# 其他错误调用原始方法
|
# 其他错误调用原始方法
|
||||||
original_handle_error(self, context, type, value, tb)
|
original_handle_error(self, context, type, value, tb)
|
||||||
@@ -35,60 +37,152 @@ try:
|
|||||||
error_str = str(e)
|
error_str = str(e)
|
||||||
if (type(e).__name__ == 'IOClosed' and 'Operation on closed file' in error_str) or \
|
if (type(e).__name__ == 'IOClosed' and 'Operation on closed file' in error_str) or \
|
||||||
(type(e).__name__ == 'EOFError') or \
|
(type(e).__name__ == 'EOFError') or \
|
||||||
(type(e).__name__ == 'OSError' and 'Bad file descriptor' in error_str):
|
(type(e).__name__ == 'OSError' and 'Bad file descriptor' in error_str) or \
|
||||||
|
(type(e).__name__ == 'OSError' and 'Socket operation on non-socket' in error_str):
|
||||||
# 优雅处理,返回继续运行
|
# 优雅处理,返回继续运行
|
||||||
return None
|
return None
|
||||||
# 其他异常重新抛出
|
# 其他异常重新抛出
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
def custom_fire_timers(self):
|
||||||
|
try:
|
||||||
|
return original_fire_timers(self)
|
||||||
|
except Exception as e:
|
||||||
|
# 捕获 fire_timers 方法中可能出现的 IOClosed 错误
|
||||||
|
error_str = str(e)
|
||||||
|
if (type(e).__name__ == 'IOClosed' and 'Operation on closed file' in error_str) or \
|
||||||
|
(type(e).__name__ == 'EOFError') or \
|
||||||
|
(type(e).__name__ == 'OSError' and 'Bad file descriptor' in error_str) or \
|
||||||
|
(type(e).__name__ == 'OSError' and 'Socket operation on non-socket' in error_str):
|
||||||
|
# 优雅处理,记录日志后继续运行
|
||||||
|
return
|
||||||
|
# 其他异常重新抛出
|
||||||
|
raise
|
||||||
|
|
||||||
# 替换原始方法
|
# 替换原始方法
|
||||||
hub.Hub.handle_error = custom_handle_error
|
hub.Hub.handle_error = custom_handle_error
|
||||||
hubs.hub.Hub.switch = custom_switch
|
hubs.hub.Hub.switch = custom_switch
|
||||||
|
hubs.hub.Hub.fire_timers = custom_fire_timers
|
||||||
|
|
||||||
# 同样处理 greenio 模块的错误
|
# 同样处理 greenio 模块的所有相关方法
|
||||||
from eventlet import greenio
|
from eventlet import greenio
|
||||||
|
|
||||||
|
# 保存原始的 greenio 方法
|
||||||
original_recv_loop = greenio.base.GreenSocket._recv_loop
|
original_recv_loop = greenio.base.GreenSocket._recv_loop
|
||||||
original_recv_into = greenio.base.GreenSocket.recv_into
|
original_recv_into = greenio.base.GreenSocket.recv_into
|
||||||
|
original_send_loop = greenio.base.GreenSocket._send_loop
|
||||||
|
original_send = greenio.base.GreenSocket.send
|
||||||
|
|
||||||
|
def safe_io_operation(io_func, *args, **kwargs):
|
||||||
|
"""安全执行 IO 操作,处理常见的 IO 错误"""
|
||||||
|
try:
|
||||||
|
return io_func(*args, **kwargs)
|
||||||
|
except Exception as e:
|
||||||
|
# 检查是否为需要忽略的 IO 错误
|
||||||
|
error_str = str(e)
|
||||||
|
is_safe_error = False
|
||||||
|
|
||||||
|
# 检查错误类型
|
||||||
|
if type(e).__name__ in ('IOClosed', 'EOFError'):
|
||||||
|
is_safe_error = True
|
||||||
|
elif type(e).__name__ == 'OSError':
|
||||||
|
# 检查具体的错误码
|
||||||
|
if hasattr(e, 'errno') and e.errno in (9, 88, 107): # Bad file descriptor, Socket operation on non-socket, Operation on closed file
|
||||||
|
is_safe_error = True
|
||||||
|
# 检查错误信息
|
||||||
|
elif any(msg in error_str for msg in ['Bad file descriptor', 'Socket operation on non-socket', 'Operation on closed file']):
|
||||||
|
is_safe_error = True
|
||||||
|
|
||||||
|
if is_safe_error:
|
||||||
|
# 根据操作类型返回适当的默认值
|
||||||
|
if 'recv' in io_func.__name__ or 'read' in io_func.__name__:
|
||||||
|
return b'' if 'recv' in io_func.__name__ else ''
|
||||||
|
elif 'send' in io_func.__name__ or 'write' in io_func.__name__:
|
||||||
|
return 0
|
||||||
|
return None
|
||||||
|
# 其他异常重新抛出
|
||||||
|
raise
|
||||||
|
|
||||||
def custom_recv_loop(self, recv_func, recv_args, *args, **kwargs):
|
def custom_recv_loop(self, recv_func, recv_args, *args, **kwargs):
|
||||||
try:
|
return safe_io_operation(original_recv_loop, self, recv_func, recv_args, *args, **kwargs)
|
||||||
return original_recv_loop(self, recv_func, recv_args, *args, **kwargs)
|
|
||||||
except (hubs.IOClosed, EOFError, OSError) as e:
|
|
||||||
# 优雅处理 IO 错误
|
|
||||||
if hasattr(e, 'errno') and e.errno in (9, 88, 107): # Bad file descriptor, Socket operation on non-socket, Operation on closed file
|
|
||||||
return b''
|
|
||||||
raise
|
|
||||||
|
|
||||||
def custom_recv_into(self, buffer, nbytes=0, flags=0):
|
def custom_recv_into(self, buffer, nbytes=0, flags=0):
|
||||||
try:
|
return safe_io_operation(original_recv_into, self, buffer, nbytes, flags)
|
||||||
return original_recv_into(self, buffer, nbytes, flags)
|
|
||||||
except OSError as e:
|
|
||||||
if hasattr(e, 'errno') and e.errno in (9, 88, 107): # Bad file descriptor, Socket operation on non-socket, Operation on closed file
|
|
||||||
return 0
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
def custom_send_loop(self, send_func, data, *args, **kwargs):
|
||||||
|
return safe_io_operation(original_send_loop, self, send_func, data, *args, **kwargs)
|
||||||
|
|
||||||
|
def custom_send(self, data, flags=0):
|
||||||
|
return safe_io_operation(original_send, self, data, flags)
|
||||||
|
|
||||||
|
# 替换 greenio 方法
|
||||||
greenio.base.GreenSocket._recv_loop = custom_recv_loop
|
greenio.base.GreenSocket._recv_loop = custom_recv_loop
|
||||||
greenio.base.GreenSocket.recv_into = custom_recv_into
|
greenio.base.GreenSocket.recv_into = custom_recv_into
|
||||||
|
greenio.base.GreenSocket._send_loop = custom_send_loop
|
||||||
|
greenio.base.GreenSocket.send = custom_send
|
||||||
|
|
||||||
# 处理 WSGI 中的 readline 错误
|
# 处理 WSGI 中的错误
|
||||||
try:
|
try:
|
||||||
import eventlet.wsgi
|
import eventlet.wsgi
|
||||||
original_wsgi_handle_one_request = eventlet.wsgi.HttpProtocol.handle_one_request
|
original_wsgi_handle_one_request = eventlet.wsgi.HttpProtocol.handle_one_request
|
||||||
|
original_wsgi_handle_one_response = eventlet.wsgi.HttpProtocol.handle_one_response
|
||||||
|
|
||||||
def custom_wsgi_handle_one_request(self):
|
def custom_wsgi_handle_one_request(self):
|
||||||
try:
|
try:
|
||||||
return original_wsgi_handle_one_request(self)
|
return original_wsgi_handle_one_request(self)
|
||||||
except OSError as e:
|
except Exception as e:
|
||||||
if hasattr(e, 'errno') and e.errno in (9, 88, 107): # Bad file descriptor, Socket operation on non-socket, Operation on closed file
|
error_str = str(e)
|
||||||
|
if (type(e).__name__ == 'IOClosed' and 'Operation on closed file' in error_str) or \
|
||||||
|
(type(e).__name__ == 'EOFError') or \
|
||||||
|
(hasattr(e, 'errno') and e.errno in (9, 88, 107)):
|
||||||
# 清理连接状态
|
# 清理连接状态
|
||||||
|
try:
|
||||||
self.finish()
|
self.finish()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return
|
||||||
|
raise
|
||||||
|
|
||||||
|
def custom_wsgi_handle_one_response(self):
|
||||||
|
try:
|
||||||
|
return original_wsgi_handle_one_response(self)
|
||||||
|
except Exception as e:
|
||||||
|
error_str = str(e)
|
||||||
|
if (type(e).__name__ == 'IOClosed' and 'Operation on closed file' in error_str) or \
|
||||||
|
(type(e).__name__ == 'EOFError') or \
|
||||||
|
(hasattr(e, 'errno') and e.errno in (9, 88, 107)):
|
||||||
|
# 清理连接状态
|
||||||
|
try:
|
||||||
|
self.finish()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
return
|
return
|
||||||
raise
|
raise
|
||||||
|
|
||||||
eventlet.wsgi.HttpProtocol.handle_one_request = custom_wsgi_handle_one_request
|
eventlet.wsgi.HttpProtocol.handle_one_request = custom_wsgi_handle_one_request
|
||||||
|
eventlet.wsgi.HttpProtocol.handle_one_response = custom_wsgi_handle_one_response
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# 如果修改失败,忽略错误
|
# 如果修改失败,忽略错误
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# 确保我们捕获所有可能的 IOClosed 错误
|
||||||
|
# 修改 eventlet 的全局异常处理
|
||||||
|
original_trampoline = hubs.trampoline
|
||||||
|
|
||||||
|
def custom_trampoline(fd, read=False, write=False, timeout=None, timeout_exc=None):
|
||||||
|
try:
|
||||||
|
return original_trampoline(fd, read, write, timeout, timeout_exc)
|
||||||
|
except Exception as e:
|
||||||
|
error_str = str(e)
|
||||||
|
if (type(e).__name__ == 'IOClosed' and 'Operation on closed file' in error_str) or \
|
||||||
|
(type(e).__name__ == 'EOFError') or \
|
||||||
|
(hasattr(e, 'errno') and e.errno in (9, 88, 107)):
|
||||||
|
# 优雅处理,返回 None
|
||||||
|
return None
|
||||||
|
# 其他异常重新抛出
|
||||||
|
raise
|
||||||
|
|
||||||
|
hubs.trampoline = custom_trampoline
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# 如果修改失败,忽略错误
|
# 如果修改失败,忽略错误
|
||||||
pass
|
pass
|
||||||
|
|||||||
Reference in New Issue
Block a user