Неожиданное поведение с django с каналами django
это api для обновления моей сессионной модели.
теперь вот потребитель
class ChatConsumer(AsyncWebsocketConsumer):
""" WebSocket consumer for handling chat messages in a specific session."""
async def connect(self):
"""Handle WebSocket connection initialization."""
self.room_name = self.scope["url_route"]["kwargs"]["room_name"]
self.room_group_name = constants.CHAT_SESSION_ROOM_GROUP_NAME.format(session_id=self.room_name)
session = await self.__get_session({"session_id": self.room_name, "session_has_ended": False})
if not session:
logger.info(f"Session [{self.room_name}] expired or does not exist")
# close the connection
await self.close()
return
self.session = session
await self.__set_attributes()
await self.channel_layer.group_add(self.room_group_name, self.channel_name)
await self.accept()
# Verify connection conditions
if not await self.__validate_connection():
await self.__send_validation_failed_message()
return
# Send intro message if no messages exist
if not await database_sync_to_async(lambda: session.has_messages)():
await self.__send_intro_message()
async def __set_attributes(self):
self.org = self.session.org
self.bot = self.session.bot
self.platform = self.bot.platform
self.language = self.bot.language
self.ai_response_url = settings.AI_BASE_URL + f'/api/v1.0/ai/conversation/{self.org.id}/{self.bot.id}'
self.goal = 'you are an intelligent customer service agent'
self.customer_name = self.session.user_name if self.session.user_name else ""
self.customer_email = self.session.user_email if self.session.user_email else ""
self.user_type = None
self.user = self.scope["user"] if not self.scope["user"].is_anonymous else None
@database_sync_to_async
def __get_session(self, filter_kwargs: dict):
"""Fetch a session with related data."""
try:
session = Session.objects.select_related(
"bot",
"org",
"bot__language",
"bot__platform"
).get(**filter_kwargs)
return session
except Exception as err:
logger.error(f"Error fetching session: {err}")
return None
теперь, когда я подключен к своему потребителю, если я попытаюсь использовать api, который я привел выше, это на самом деле не обновит базу данных, но если я не подключен к своему потребителю, то api работает
более подробно, если я попытаюсь обновить эти поля через django admin при подключении к потребителю, обновление будет работать нормально, но оно не будет работать с api, который я создал
и самый неожиданный сценарий - если я удалю `self.org` из consumer, то api заработает, что-то связано с моделью организации, которую я пытаюсь извлечь
если я удалю ту часть, где я отправляю сообщение на канальный уровень через api, то обновление сработает
я пробовал выполнять фоновую задачу, но у меня ничего не получилось
Проблема возникает из-за того, что пользователь WebSocket хранит объекты базы данных (self.org, self.session) в памяти, что создает конфликты соединений с вашим синхронным API.
Это хорошо документированная проблема Django Channels, связанная с изоляцией соединения с базой данных между контекстами асинхронности и синхронизации. Для получения более подробной информации ознакомьтесь с документацией Django Channels.
Чтобы решить вашу проблему, попробуйте заменить хранилище объектов базы данных в вашем пользовательском методе __set_attributes(), который у вас есть, следующим образом:
async def __set_attributes(self):
# DON'T store database objects - which causes connection conflicts
# self.org = self.session.org # Remove this
# self.bot = self.session.bot # Remove this
# DO store only IDs and refresh data when needed
session = await self.__get_session({"session_id": self.session_id})
if not session:
return
self.org_id = session.org.id
self.bot_id = session.bot.id
self.ai_response_url = settings.AI_BASE_URL + f'/api/v1.0/ai/conversation/{session.org.id}/{session.bot.id}'
# ... rest of your attributes
async def __get_fresh_session(self):
"""Get fresh session data from database when needed."""
return await self.__get_session({"session_id": self.session_id})
Сохраняя только IDs вместо полных объектов базы данных, вы предотвращаете сохранение пользователем устаревших подключений к базе данных, которые конфликтуют с вашими синхронными операциями API.
Надеюсь, это решит вашу проблему.