修复了code-server-like服务中的eventlet.hubs.IOClosed错误:当客户端断开连接时,文件描述符被关闭,但后台任务仍在尝试读取,导致eventlet核心代码抛出IOClosed错误。

This commit is contained in:
CakeCN
2026-01-06 21:05:39 +08:00
parent 643c16fdf7
commit 761095d61d
2 changed files with 37 additions and 15 deletions

View File

@@ -67,21 +67,35 @@ def read_and_forward_pty_output(fd=None, pid=None, room_id=None,namespace=None):
return
if fd:
timeout_sec = 0
(data_ready, _, _) = select.select([fd], [], [], timeout_sec)
if data_ready:
# output = os.read(fd, max_read_bytes).decode('ascii')
timeout=0.1
try:
output = os.read(fd, max_read_bytes).decode()
except Exception as err:
output = """
***AQUI WEB TERM ERR***
{}
***********************
""".format(err)
# the key for different visitor to get different terminal (instead of mixing up)
# is to let the background task push pty response to each one's own (default) ROOM!
namespace.emit("pty_output", {"output": output}, room=room_id)
try:
# Check if file descriptor is still valid by trying to select on it
(data_ready, _, _) = select.select([fd], [], [], timeout_sec)
if data_ready:
timeout=0.1
try:
output = os.read(fd, max_read_bytes).decode()
except (OSError, IOError, EOFError) as err:
# File descriptor closed or other IO error, exit gracefully
return
except UnicodeDecodeError as err:
output = """
***AQUI WEB TERM ERR***
Unicode decode error: {}
***********************
""".format(err)
# the key for different visitor to get different terminal (instead of mixing up)
# is to let the background task push pty response to each one's own (default) ROOM!
try:
namespace.emit("pty_output", {"output": output}, room=room_id)
except Exception:
# If emit fails, the client is probably disconnected, exit
return
except (OSError, IOError) as err:
# File descriptor closed or invalid, exit gracefully
return
except Exception as e:
# Catch any other unexpected exceptions to prevent server crash
pass
finally:
# Clean up file descriptor if it's open
if fd:

View File

@@ -1,5 +1,12 @@
from app import create_app
from app.extensions import socketio
import logging
# 配置日志减少eventlet的调试日志
logging.getLogger('eventlet').setLevel(logging.ERROR)
logging.getLogger('socketio').setLevel(logging.ERROR)
logging.getLogger('werkzeug').setLevel(logging.ERROR)
app = create_app()
if __name__ == '__main__':
@@ -9,4 +16,5 @@ if __name__ == '__main__':
port=5200,
debug=False, # 开发期打开
allow_unsafe_werkzeug=True, # 避免 dev server 的安全限制提示
log_output=False # 禁用详细输出
)