docs: Добавлен лог сессии от 28.10.2025 - исправление SSE error handling

This commit is contained in:
AI Assistant
2025-10-28 00:47:03 +03:00
parent 0b75e01b9e
commit 90ab969de0

356
SESSION_LOG_2025-10-28.md Normal file
View File

@@ -0,0 +1,356 @@
# 📋 Лог сессии: Исправление SSE error handling
**Дата:** 28 октября 2025 (00:00 - 01:00 MSK)
**Задача:** Исправление ошибки "Ошибка подключения к серверу" при успешном распознавании полиса
**Статус:** ✅ Успешно завершено
---
## 🎯 Проблема
После успешного распознавания полиса через OCR/Vision, пользователь видел модальное окно с ошибкой:
```
❌ Ошибка распознавания
Ошибка подключения к серверу
Полный ответ: null
```
Хотя в логах backend видно, что:
- ✅ SSE подключение установлено
- ✅ Событие OCR получено из Redis
- ✅ Данные отправлены клиенту
- ✅ SSE соединение закрыто корректно
---
## 🔍 Диагностика
### Backend логи показывали успешную работу:
```
2025-10-28 00:41:15,187 - 🚀 SSE connection requested for task_id: CLM-2025-10-27-Y1KWA1
2025-10-28 00:41:15,202 - 📡 Client subscribed to ocr_events:CLM-2025-10-27-Y1KWA1
2025-10-28 00:41:15,203 - ⏳ Waiting for message on ocr_events:CLM-2025-10-27-Y1KWA1...
2025-10-28 00:41:49,729 - 📥 Received message type: message
2025-10-28 00:41:49,729 - 📦 Raw event data: {"claim_id":"CLM-2025-10-27-Y1KWA1","event":{"event_type":"ocr_completed","status":"completed","message":"OCR обработка завершена","data":{"output":{"is_policy":"yes","policy_number":"E1000-302545808"...
2025-10-28 00:41:49,730 - 📦 Unwrapped n8n Redis format for CLM-2025-10-27-Y1KWA1
2025-10-28 00:41:49,730 - 📤 Sending event to client: completed
2025-10-28 00:41:49,730 - ✅ Task CLM-2025-10-27-Y1KWA1 finished, closing SSE
```
**Вывод:** Backend работал корректно!
### Причина ошибки:
1. Backend отправляет событие OCR клиенту
2. Backend **закрывает SSE соединение** (это нормально)
3. Браузер получает событие закрытия SSE
4. Браузер триггерит `eventSource.onerror`
5. Frontend в `onerror` **перезаписывает успешный результат** ошибкой:
```typescript
// ❌ СТАРЫЙ КОД (неправильный)
eventSource.onerror = (error) => {
console.error('❌ SSE connection error:', error);
setOcrModalContent({
success: false,
data: null,
message: 'Ошибка подключения к серверу'
});
setWaitingForOcr(false);
eventSource.close();
};
```
**Проблема:** `onerror` вызывается **после** получения результата, когда backend закрывает SSE, и затирает успешный результат.
---
## 🛠️ Решение
Добавил проверку в `eventSource.onerror` — если уже получили результат OCR, не затираем его сообщением об ошибке:
```typescript
// ✅ НОВЫЙ КОД (правильный)
eventSource.onerror = (error) => {
console.error('❌ SSE connection error:', error);
console.error('SSE readyState:', eventSource.readyState);
// Не показываем ошибку если уже получили результат (backend закрыл SSE после успешной отправки)
setOcrModalContent((prev) => {
if (prev && prev !== 'loading') {
console.log('✅ SSE закрыто после получения результата, не показываем ошибку');
return prev; // Оставляем текущий результат
}
return { success: false, data: null, message: 'Ошибка подключения к серверу' };
});
setWaitingForOcr(false);
eventSource.close();
};
```
**Логика:**
- Если `prev !== 'loading'` → значит уже получили результат → **не затираем** его
- Если `prev === 'loading'` → реальная ошибка подключения → показываем ошибку
---
## 📝 Изменённые файлы
### `/frontend/src/components/form/Step1Policy.tsx`
**Изменение:** Обработка `eventSource.onerror` с проверкой наличия результата
**Строки:** 147-162
**Было:**
```typescript
eventSource.onerror = (error) => {
console.error('❌ SSE connection error:', error);
setOcrModalContent({ success: false, data: null, message: 'Ошибка подключения к серверу' });
setWaitingForOcr(false);
eventSource.close();
};
```
**Стало:**
```typescript
eventSource.onerror = (error) => {
console.error('❌ SSE connection error:', error);
console.error('SSE readyState:', eventSource.readyState);
setOcrModalContent((prev) => {
if (prev && prev !== 'loading') {
console.log('✅ SSE закрыто после получения результата, не показываем ошибку');
return prev;
}
return { success: false, data: null, message: 'Ошибка подключения к серверу' };
});
setWaitingForOcr(false);
eventSource.close();
};
```
---
## 🐛 Проблемы в процессе исправления
### Проблема 1: Backend завис после kill -HUP
**Симптом:**
```bash
ERROR: [Errno 98] Address already in use
```
**Причина:** `kill -HUP` не перезапустил uvicorn корректно, порт 8100 остался занят зависшим процессом.
**Решение:**
```bash
# Убили все процессы на порту 8100
sudo lsof -ti :8100 | xargs -r kill -9
# Перезапустили backend
cd /var/www/fastuser/data/www/crm.clientright.ru/erv_platform/backend
source venv/bin/activate
python -m uvicorn app.main:app --host 0.0.0.0 --port 8100 --reload > ../backend.log 2>&1 &
```
### Проблема 2: Изменения не применились во frontend
**Симптом:** После `docker-compose restart frontend` старый код всё ещё работал.
**Причина:** Frontend работает в Docker без volume mount — код встроен в образ при сборке.
**Решение:**
```bash
# Пересборка образа с новым кодом
docker-compose build frontend
# Пересоздание контейнера
docker-compose up -d frontend
```
**Проверка применения изменений:**
```bash
docker exec erv_platform_frontend_1 grep -A8 "eventSource.onerror" /app/src/components/form/Step1Policy.tsx
```
---
## 🚀 Git Commit
**Commit:** `0b75e01`
**Message:** "fix: Не затираем результат OCR при закрытии SSE соединения"
**Полное описание:**
```
Проблема: Backend закрывает SSE после отправки события, браузер триггерит onerror,
фронтенд перезаписывал успешный результат сообщением 'Ошибка подключения к серверу'.
Решение: Проверяем в onerror что если уже получили результат (prev !== 'loading'),
не затираем его ошибкой.
```
**Push:**`origin/main`
---
## ✅ Результат
### Что работает:
1. ✅ Backend запущен (PID 25931) на порту 8100
2. ✅ Frontend пересобран и работает на http://147.45.146.17:5173
3. ✅ SSE подключение устанавливается корректно
4. ✅ События OCR получаются из Redis через backend
5. ✅ Результат распознавания отображается в модальном окне
6.**Ошибка "Ошибка подключения к серверу" больше не появляется**
7. ✅ Git репозиторий синхронизирован
### Тестирование:
**Сценарий 1: Успешное распознавание полиса**
- Загрузка файла полиса → ✅
- SSE подключение → ✅
- OCR/Vision обработка → ✅
- Отображение результата → ✅ "Полис распознан: E1000-302545808"
- **Нет ошибки** при закрытии SSE → ✅
**Сценарий 2: Загрузка неподходящего документа**
- Загрузка не-полиса → ✅
- SSE подключение → ✅
- OCR/Vision обработка → ✅
- Отображение: "Документ не является полисом ERV" → ✅
**Сценарий 3: Реальная ошибка подключения**
- Если backend недоступен → ❌ "Ошибка подключения к серверу" (корректная ошибка)
---
## 📊 Архитектура (финальная)
```
┌─────────────────────────────────────────────────────────────────────┐
│ USER BROWSER │
│ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ React Frontend (Vite Dev Server, port 3000) │ │
│ │ - Step1Policy.tsx (SSE Client) │ │
│ │ - Модалка с результатом OCR │ │
│ │ - EventSource(`/events/${claimId}`) │ │
│ │ - ✅ Защита от затирания результата в onerror │ │
│ └────────────┬─────────────────────────────────────────────────┘ │
│ │ Vite Proxy (/events → host:8100) │
└───────────────┼─────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ BACKEND (FastAPI, port 8100) │
│ PID: 25931 │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ SSE Endpoint: GET /events/{task_id} │ │
│ │ - Подписка на Redis: ocr_events:{task_id} │ │
│ │ - Стриминг событий через SSE │ │
│ │ - Закрытие SSE после отправки результата │ │
│ └────────────┬─────────────────────────────────────────────────┘ │
└───────────────┼──────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ Redis Pub/Sub (crm.clientright.ru:6379) │
│ │
│ Channel: ocr_events:CLM-2025-10-27-XXXXX │
│ Format: { │
│ "claim_id": "CLM-...", │
│ "event": { │
│ "event_type": "ocr_completed", │
│ "status": "completed", │
│ "data": { "output": { "is_policy": "yes", ... } } │
│ } │
│ } │
└────────────────▲────────────────────────────────────────────────────┘
│ PUBLISH
┌────────────────┴────────────────────────────────────────────────────┐
│ n8n Workflow (OCR Processing) │
│ │
│ 1. Webhook trigger (file upload) │
│ 2. Upload to S3 │
│ 3. OCR Service (147.45.146.17:8001) │
│ 4. AI Vision (OpenRouter Gemini 2.0 Flash) │
│ 5. Redis Publish Node → ocr_events:{claim_id} │
└─────────────────────────────────────────────────────────────────────┘
```
---
## 📈 Метрики
**Время выполнения сессии:** ~1 час
**Количество коммитов:** 1
**Изменённых файлов:** 1
**Строк изменено:** +10 / -1
**Перезапусков backend:** 2
**Rebuild frontend:** 1
**Проблемы решены:**
- ✅ Затирание результата OCR при закрытии SSE
- ✅ Backend завис после kill -HUP
- ✅ Изменения не применялись без rebuild
---
## 🔗 Ссылки
- Frontend: http://147.45.146.17:5173
- Backend API: http://localhost:8100
- Backend Health: http://localhost:8100/health
- Gitea: http://147.45.146.17:3002/negodiy/erv-platform
- n8n: http://147.45.146.17:5678
---
## 📝 Важные заметки
### Backend запущен вне Docker:
```bash
# Процесс
PID: 25931
Command: python -m uvicorn app.main:app --host 0.0.0.0 --port 8100 --reload
# Логи
tail -f /var/www/fastuser/data/www/crm.clientright.ru/erv_platform/backend.log
# Перезапуск
cd /var/www/fastuser/data/www/crm.clientright.ru/erv_platform/backend
source venv/bin/activate
python -m uvicorn app.main:app --host 0.0.0.0 --port 8100 --reload > ../backend.log 2>&1 &
```
### Frontend требует rebuild при изменениях:
```bash
# Применение изменений
docker-compose build frontend
docker-compose up -d frontend
# Проверка кода в контейнере
docker exec erv_platform_frontend_1 cat /app/src/components/form/Step1Policy.tsx
```
### Redis credentials:
```
Host: crm.clientright.ru
Port: 6379
Password: cKSq8M11ZQIRi59OuUXb
Channels: ocr_events:{claim_id}
```
---
**Статус:** ✅ Успешно завершено
**Автор:** AI Assistant (Claude Sonnet 4.5)
**Дата:** 28 октября 2025, 01:00 MSK