16 KiB
📋 Лог сессии: Исправление 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 работал корректно!
Причина ошибки:
- Backend отправляет событие OCR клиенту
- Backend закрывает SSE соединение (это нормально)
- Браузер получает событие закрытия SSE
- Браузер триггерит
eventSource.onerror - Frontend в
onerrorперезаписывает успешный результат ошибкой:
// ❌ СТАРЫЙ КОД (неправильный)
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, не затираем его сообщением об ошибке:
// ✅ НОВЫЙ КОД (правильный)
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
Было:
eventSource.onerror = (error) => {
console.error('❌ SSE connection error:', error);
setOcrModalContent({ success: false, data: null, message: 'Ошибка подключения к серверу' });
setWaitingForOcr(false);
eventSource.close();
};
Стало:
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
Симптом:
ERROR: [Errno 98] Address already in use
Причина: kill -HUP не перезапустил uvicorn корректно, порт 8100 остался занят зависшим процессом.
Решение:
# Убили все процессы на порту 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 — код встроен в образ при сборке.
Решение:
# Пересборка образа с новым кодом
docker-compose build frontend
# Пересоздание контейнера
docker-compose up -d frontend
Проверка применения изменений:
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
✅ Результат
Что работает:
- ✅ Backend запущен (PID 25931) на порту 8100
- ✅ Frontend пересобран и работает на http://147.45.146.17:5173
- ✅ SSE подключение устанавливается корректно
- ✅ События OCR получаются из Redis через backend
- ✅ Результат распознавания отображается в модальном окне
- ✅ Ошибка "Ошибка подключения к серверу" больше не появляется
- ✅ 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:
# Процесс
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 при изменениях:
# Применение изменений
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