diff --git a/backend/open_webui/routers/terminals.py b/backend/open_webui/routers/terminals.py index 4c61d6ec1d..6a942cf9b2 100644 --- a/backend/open_webui/routers/terminals.py +++ b/backend/open_webui/routers/terminals.py @@ -331,11 +331,20 @@ async def ws_terminal( except Exception: pass - await asyncio.gather( - _client_to_upstream(), - _upstream_to_client(), - return_exceptions=True, - ) + # End the proxy as soon as either direction finishes (e.g. a + # graceful upstream CLOSE) and cancel the sibling, which would + # otherwise hang on a blocked ws.receive() until the browser leaves. + tasks = [ + asyncio.create_task(_client_to_upstream()), + asyncio.create_task(_upstream_to_client()), + ] + _done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) + for task in pending: + task.cancel() + try: + await task + except asyncio.CancelledError: + pass except Exception as e: log.exception('Terminal WebSocket proxy error: %s', e) finally: