import eventlet from eventlet import greenio import logging import traceback # 获取当前 socketio 实例并配置错误处理 import sys # 配置 eventlet 日志,抑制 IOClosed 等错误日志 logging.getLogger('eventlet.hubs').setLevel(logging.CRITICAL) logging.getLogger('eventlet.greenio').setLevel(logging.CRITICAL) # 进行猴子补丁操作 eventlet.monkey_patch() # 配置 eventlet 以更优雅地处理错误,避免疯狂报错 try: # 1. 首先,禁用 eventlet 的调试日志,减少输出 logging.getLogger('eventlet').setLevel(logging.CRITICAL) logging.getLogger('socketio').setLevel(logging.CRITICAL) logging.getLogger('werkzeug').setLevel(logging.CRITICAL) # 2. 配置 eventlet 相关设置(移除了不存在的debug属性) # 3. 避免重复打印相同错误的机制 seen_errors = set() max_error_logs = 5 # 每个错误最多打印5次 error_counts = {} def is_duplicate_error(e): """检查是否为重复错误""" error_key = f"{type(e).__name__}: {e}" if error_key in seen_errors: error_counts[error_key] = error_counts.get(error_key, 0) + 1 if error_counts[error_key] > max_error_logs: return True else: seen_errors.add(error_key) error_counts[error_key] = 1 return False # 4. 只修改关键的 greenio 方法,确保在致命错误时彻底关闭连接 # 增强 socketio 错误处理,确保不会因为单个连接错误而宕机 try: original_excepthook = sys.excepthook def custom_excepthook(exc_type, exc_value, exc_traceback): """全局异常钩子,捕获所有未处理的异常""" if exc_type.__name__ in ['OSError', 'IOError'] and 'Bad file descriptor' in str(exc_value): # 处理 Bad file descriptor 错误,不导致服务器宕机 if not is_duplicate_error(exc_value): print(f"[Global Error Handler] {exc_type.__name__}: {exc_value}") print("[Traceback]") traceback.print_exception(exc_type, exc_value, exc_traceback) # 不调用原始的 excepthook,防止服务器宕机 return # 其他异常调用原始的 excepthook original_excepthook(exc_type, exc_value, exc_traceback) # 设置全局异常钩子 sys.excepthook = custom_excepthook except Exception as e: # 如果修改失败,忽略错误 print(f"[Global Excepthook Patch Error] {e}") # 保存并替换原始的 greenio 方法 if hasattr(greenio.base.GreenSocket, '_recv_loop'): original_recv_loop = greenio.base.GreenSocket._recv_loop def custom_recv_loop(self, recv_func, recv_args, *args, **kwargs): try: return original_recv_loop(self, recv_func, recv_args, *args, **kwargs) except Exception as e: if not is_duplicate_error(e): print(f"[Eventlet IO Error] _recv_loop: {type(e).__name__}: {e}") print("[Traceback]") traceback.print_exc() # 彻底关闭连接,不再继续处理 try: self.close() except Exception: pass return b'' greenio.base.GreenSocket._recv_loop = custom_recv_loop if hasattr(greenio.base.GreenSocket, 'recv_into'): original_recv_into = greenio.base.GreenSocket.recv_into def custom_recv_into(self, buffer, nbytes=0, flags=0): try: return original_recv_into(self, buffer, nbytes, flags) except Exception as e: if not is_duplicate_error(e): print(f"[Eventlet IO Error] recv_into: {type(e).__name__}: {e}") print("[Traceback]") traceback.print_exc() # 彻底关闭连接,不再继续处理 try: self.close() except Exception: pass return 0 greenio.base.GreenSocket.recv_into = custom_recv_into if hasattr(greenio.base.GreenSocket, '_send_loop'): original_send_loop = greenio.base.GreenSocket._send_loop def custom_send_loop(self, send_func, data, *args, **kwargs): try: return original_send_loop(self, send_func, data, *args, **kwargs) except Exception as e: if not is_duplicate_error(e): print(f"[Eventlet IO Error] _send_loop: {type(e).__name__}: {e}") print("[Traceback]") traceback.print_exc() # 彻底关闭连接,不再继续处理 try: self.close() except Exception: pass return 0 greenio.base.GreenSocket._send_loop = custom_send_loop if hasattr(greenio.base.GreenSocket, 'send'): original_send = greenio.base.GreenSocket.send def custom_send(self, data, flags=0): try: return original_send(self, data, flags) except Exception as e: if not is_duplicate_error(e): print(f"[Eventlet IO Error] send: {type(e).__name__}: {e}") print("[Traceback]") traceback.print_exc() # 彻底关闭连接,不再继续处理 try: self.close() except Exception: pass return 0 greenio.base.GreenSocket.send = custom_send # 5. 处理 WSGI 中的错误,确保彻底清理 try: import eventlet.wsgi if hasattr(eventlet.wsgi.HttpProtocol, 'handle_one_request'): original_wsgi_handle_one_request = eventlet.wsgi.HttpProtocol.handle_one_request def custom_wsgi_handle_one_request(self): try: return original_wsgi_handle_one_request(self) except Exception as e: if not is_duplicate_error(e): print(f"[Eventlet WSGI Request Error] {type(e).__name__}: {e}") print("[Traceback]") traceback.print_exc() # 彻底清理连接,不再继续 try: self.rfile.close() self.wfile.close() self.finish() except Exception: pass return eventlet.wsgi.HttpProtocol.handle_one_request = custom_wsgi_handle_one_request if hasattr(eventlet.wsgi.HttpProtocol, 'handle_one_response'): original_wsgi_handle_one_response = eventlet.wsgi.HttpProtocol.handle_one_response def custom_wsgi_handle_one_response(self): try: return original_wsgi_handle_one_response(self) except Exception as e: if not is_duplicate_error(e): print(f"[Eventlet WSGI Response Error] {type(e).__name__}: {e}") print("[Traceback]") traceback.print_exc() # 彻底清理连接,不再继续 try: self.rfile.close() self.wfile.close() self.finish() except Exception: pass return eventlet.wsgi.HttpProtocol.handle_one_response = custom_wsgi_handle_one_response except Exception as e: # 如果修改失败,忽略错误 print(f"[WSGI Patch Error] {e}") print("[Eventlet Error Handling] Configured to handle errors gracefully, avoiding duplicate logs") except Exception as e: # 如果修改失败,打印错误但继续运行 print(f"[Eventlet Patch Initialization Error] {e}") traceback.print_exc() from flask import Flask from .views.routes import main_bp from .views.file import file_bp from .config import Config from .extensions import init_extensions,register_namespaces def create_app(): app = Flask(__name__, template_folder="../templates", static_folder="../static",static_url_path="/vsc-like/static") app.config.from_object(Config) @app.route('/') def hello(): return 'Hello, World!' # 注册蓝图 app.register_blueprint(main_bp) app.register_blueprint(file_bp) # 初始化SocketIO init_extensions(app) register_namespaces(app) return app