diff --git a/backend/open_webui/routers/chats.py b/backend/open_webui/routers/chats.py index 256455fffb..c618334783 100644 --- a/backend/open_webui/routers/chats.py +++ b/backend/open_webui/routers/chats.py @@ -30,6 +30,7 @@ from open_webui.models.folders import Folders from open_webui.models.shared_chats import SharedChatResponse, SharedChats from open_webui.models.tags import TagModel, Tags from open_webui.socket.main import get_event_emitter +from open_webui.tasks import stop_item_tasks from open_webui.utils.access_control import filter_allowed_access_grants, has_permission from open_webui.utils.auth import get_admin_user, get_verified_user from open_webui.utils.middleware import serialize_output @@ -1116,6 +1117,10 @@ async def delete_chat_by_id( user=Depends(get_verified_user), db: AsyncSession = Depends(get_async_session), ): + # Cancel any in-flight LLM tasks (streaming, title/tags generation) + # before deleting the chat to prevent orphaned requests. + await stop_item_tasks(request.app.state.redis, id) + if user.role == 'admin': chat = await Chats.get_chat_by_id(id, db=db) if not chat: @@ -1305,13 +1310,20 @@ async def clone_shared_chat_by_id( @router.post('/{id}/archive', response_model=ChatResponse | None) -async def archive_chat_by_id(id: str, user=Depends(get_verified_user), db: AsyncSession = Depends(get_async_session)): +async def archive_chat_by_id( + request: Request, + id: str, + user=Depends(get_verified_user), + db: AsyncSession = Depends(get_async_session), +): chat = await Chats.get_chat_by_id_and_user_id(id, user.id, db=db) if chat: chat = await Chats.toggle_chat_archive_by_id(id, db=db) tag_ids = chat.meta.get('tags', []) if chat.archived: + # Cancel any in-flight LLM tasks before archiving + await stop_item_tasks(request.app.state.redis, id) # Archived chats are excluded from count — clean up orphans await Chats.delete_orphan_tags_for_user(tag_ids, user.id, db=db) else: diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index a91dd31bd6..fa6e1bddb3 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -3070,7 +3070,10 @@ async def background_tasks_handler(ctx): and not metadata.get('chat_id', '').startswith('channel:') ): messages_map = await Chats.get_messages_map_by_chat_id(metadata['chat_id']) - message = messages_map.get(metadata['message_id']) if messages_map else None + if not messages_map: + # Chat was deleted while the response was streaming — skip background tasks + return + message = messages_map.get(metadata['message_id']) message_list = get_message_list(messages_map, metadata['message_id'])