fix: send and recive message

This commit is contained in:
2026-05-09 10:16:15 +03:00
parent cbd764f76b
commit 0e7709c95e
8 changed files with 624 additions and 42 deletions
+110
View File
@@ -0,0 +1,110 @@
# Исправление проблемы с отправкой сообщений
## Проблема
Когда пользователь отправлял сообщение, оно не появлялось в чате ни у отправителя, ни у получателя до перезагрузки страницы.
## Корневые причины
### 1. **Backend - Порядок операций**
В файле [backend/app/chats/service.py](backend/app/chats/service.py):
- Сообщения отправлялись через WebSocket **ДО** коммита в БД
- Это могло привести к отправке неполных или незапомненных данных
**Исправление:** Перемещены вызовы `await session.commit()` **перед** `await cls._send_ws_message()` во всех трех методах:
- `send_message()` - отправка нового сообщения
- `update_message()` - редактирование сообщения
- `delete_message()` - удаление сообщения
### 2. **Frontend - Отсутствие оптимистичного обновления**
В файле [frontend/src/pages/ChatPage.tsx](frontend/src/pages/ChatPage.tsx):
- Приложение ждало получения сообщения через WebSocket перед показом в UI
- Без WebSocket подписки или задержки сообщение не отображалось
**Исправление:** Добавлено оптимистичное обновление UI:
- Сообщение добавляется в UI **сразу** после отправки с временным ID (`temp-{timestamp}`)
- При получении подтверждения через WebSocket, временное сообщение заменяется на реальное
- Если отправка завершится с ошибкой, временное сообщение удаляется
### 3. **Backend - Логирование и обработка ошибок**
В файле [backend/app/services/messenger_service.py](backend/app/services/messenger_service.py):
- Добавлена обработка исключений при отправке WebSocket сообщений
- Улучшено логирование (удален `print("test")`, заменен на `log.info()`)
## Что изменилось
### Backend (3 файла)
1. **service.py** - 3 исправления:
- `send_message()`: commit перед WebSocket отправкой
- `update_message()`: commit перед WebSocket отправкой
- `delete_message()`: commit перед WebSocket отправкой
2. **messenger_service.py** - 2 исправления:
- Добавлен try-catch в `handle_message()`
- Заменено логирование с `print()` на `log.info()`
### Frontend (1 файл)
1. **ChatPage.tsx** - 2 исправления:
- `handleSendMessage()`: добавлено оптимистичное обновление UI
- `ws.onmessage()`: улучшена логика замены временных сообщений на реальные
## Поток отправки сообщения (новый)
```
1. Пользователь нажимает "Отправить"
2. Frontend создает временное сообщение (temp-ID) и добавляет в UI
3. Frontend отправляет запрос к backend (/chats/message)
4. Backend сохраняет сообщение в БД
5. Backend коммитит транзакцию в БД
6. Backend отправляет сообщение в Redis (pub/sub)
7. Redis PubSub listener отправляет WebSocket всем участникам чата
8. Frontend получает сообщение через WebSocket и заменяет temp-сообщение на реальное
9. UI обновлена и синхронизирована со всеми участниками
```
## Тестирование
1. **Базовое тестирование:**
- Откройте приложение в 2 браузерах для разных пользователей
- Отправьте сообщение из первого браузера
- Сообщение должно появиться **сразу** в обоих браузерах
- НЕ требуется перезагрузка страницы
2. **Проверка временных сообщений:**
- В DevTools откройте Console
- Ищите сообщение вида `temp-TIMESTAMP` в начальном списке
- После получения WebSocket ответа, ID должно измениться на UUID
3. **Проверка обновлений:**
- Отредактируйте сообщение
- Изменение должно появиться сразу у обоих пользователей
4. **Проверка удаления:**
- Удалите сообщение
- Оно должно исчезнуть сразу у обоих пользователей
## Возможные проблемы и решения
### Проблема: Сообщения все еще не появляются
**Решение:** Проверьте:
1. Redis работает (`docker ps | grep redis`)
2. Backend логирует: "Starting Redis PubSub subscriber"
3. WebSocket подключение открыто (`ws.onopen` в Console)
4. Сообщение отправляется: смотрите сетевые запросы в DevTools
### Проблема: Дублирование сообщений
**Решение:** Может быть, если:
1. Сообщение приходит через WebSocket и добавляется дважды
2. Проверьте логику замены temp-сообщений в `onmessage`
### Проблема: Сообщение показывается с ошибкой
**Решение:**
1. Проверьте формат данных в backend (логи Redis)
2. Убедитесь, что Message тип совпадает со схемой