Files
aiform_dev/SESSION_LOG_2025-10-28.md

16 KiB
Raw Blame History

📋 Лог сессии: Исправление 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 перезаписывает успешный результат ошибкой:
// ❌ СТАРЫЙ КОД (неправильный)
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


Результат

Что работает:

  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

🔗 Ссылки


📝 Важные заметки

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