diff --git a/code-server-like/app/__init__.py b/code-server-like/app/__init__.py index 0d12ba0..8578ae2 100644 --- a/code-server-like/app/__init__.py +++ b/code-server-like/app/__init__.py @@ -13,16 +13,18 @@ try: from eventlet.hubs import hub from eventlet import hubs - # 保存原始的 handle_error 方法 + # 保存原始的方法 original_handle_error = hub.Hub.handle_error original_switch = hubs.hub.Hub.switch + original_fire_timers = hubs.hub.Hub.fire_timers def custom_handle_error(self, context, type, value, tb): # 忽略 IOClosed 错误和相关的 EOFError error_str = str(value) if (type.__name__ == 'IOClosed' and 'Operation on closed file' in error_str) 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 # 其他错误调用原始方法 original_handle_error(self, context, type, value, tb) @@ -35,60 +37,152 @@ try: 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): + (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 # 其他异常重新抛出 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 hubs.hub.Hub.switch = custom_switch + hubs.hub.Hub.fire_timers = custom_fire_timers - # 同样处理 greenio 模块的错误 + # 同样处理 greenio 模块的所有相关方法 from eventlet import greenio + + # 保存原始的 greenio 方法 original_recv_loop = greenio.base.GreenSocket._recv_loop 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): - try: - 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 + return safe_io_operation(original_recv_loop, self, recv_func, recv_args, *args, **kwargs) def custom_recv_into(self, buffer, nbytes=0, flags=0): - try: - 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 + return safe_io_operation(original_recv_into, self, buffer, nbytes, flags) + 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_into = custom_recv_into + greenio.base.GreenSocket._send_loop = custom_send_loop + greenio.base.GreenSocket.send = custom_send - # 处理 WSGI 中的 readline 错误 + # 处理 WSGI 中的错误 try: import eventlet.wsgi 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): try: return original_wsgi_handle_one_request(self) - 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 + 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)): # 清理连接状态 - self.finish() + try: + 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 raise 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: # 如果修改失败,忽略错误 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: # 如果修改失败,忽略错误 pass