Problem:
- After wizard form submission, need to wait for claim data from n8n
- Claim data comes via Redis channel claim:plan:{session_token}
- Need to display confirmation form with claim data
Solution:
1. Backend: Added SSE endpoint /api/v1/claim-plan/{session_token}
- Subscribes to Redis channel claim:plan:{session_token}
- Streams claim data from n8n to frontend
- Handles timeouts and errors gracefully
2. Frontend: Added subscription to claim:plan channel
- StepWizardPlan: After form submission, subscribes to SSE
- Waits for claim_plan_ready event
- Shows loading message while waiting
- On success: saves claimPlanData and shows confirmation step
3. New component: StepClaimConfirmation
- Displays claim confirmation form in iframe
- Receives claimPlanData from parent
- Generates HTML form (placeholder - should call n8n for real HTML)
- Handles confirmation/cancellation via postMessage
4. ClaimForm: Added conditional step for confirmation
- Shows StepClaimConfirmation when showClaimConfirmation=true
- Step appears after StepWizardPlan
- Only visible when claimPlanData is available
Flow:
1. User fills wizard form → submits
2. Form data sent to n8n via /api/v1/claims/wizard
3. Frontend subscribes to SSE /api/v1/claim-plan/{session_token}
4. n8n processes data → publishes to Redis claim:plan:{session_token}
5. Backend receives → streams to frontend via SSE
6. Frontend receives → shows StepClaimConfirmation
7. User confirms → proceeds to next step
Files:
- backend/app/api/events.py: Added stream_claim_plan endpoint
- frontend/src/components/form/StepWizardPlan.tsx: Added subscribeToClaimPlan
- frontend/src/components/form/StepClaimConfirmation.tsx: New component
- frontend/src/pages/ClaimForm.tsx: Added confirmation step to steps array
201 lines
7.1 KiB
Markdown
201 lines
7.1 KiB
Markdown
# Redis vs PostgreSQL: Когда что использовать?
|
||
|
||
## Скорость доступа
|
||
|
||
### Redis:
|
||
- ⚡ **0.1-1 мс** (данные в памяти)
|
||
- Мгновенный доступ
|
||
- Идеально для частых чтений
|
||
|
||
### PostgreSQL:
|
||
- 🐢 **1-10 мс** (с индексами)
|
||
- Зависит от нагрузки и индексов
|
||
- Но всё равно очень быстро
|
||
|
||
---
|
||
|
||
## Когда Redis имеет смысл
|
||
|
||
### ✅ Используй Redis, если:
|
||
|
||
1. **Очень частые чтения** (каждый запрос, каждый клик)
|
||
- Например: счетчики, rate limiting, сессии
|
||
|
||
2. **Временные данные** (TTL, автоочистка)
|
||
- Например: SMS коды, временные токены
|
||
|
||
3. **Кеширование результатов запросов**
|
||
- Например: результаты AI классификации, шаблоны визардов
|
||
|
||
4. **Pub/Sub события** (реал-тайм)
|
||
- Например: `ocr_events:{claim_id}` для SSE
|
||
|
||
---
|
||
|
||
## Когда PostgreSQL достаточно
|
||
|
||
### ✅ Используй только PostgreSQL, если:
|
||
|
||
1. **Данные читаются не так часто**
|
||
- Загрузка страницы, переход между шагами
|
||
- Пользователь не заметит разницу 1-10 мс
|
||
|
||
2. **Важна консистентность**
|
||
- Нужна гарантия актуальности данных
|
||
- Нет риска рассинхронизации
|
||
|
||
3. **Данные уже в PostgreSQL**
|
||
- Не нужно дублировать
|
||
- Проще архитектура
|
||
|
||
---
|
||
|
||
## Для веб-формы: Анализ использования
|
||
|
||
### Когда читаются данные заявки:
|
||
|
||
1. **При загрузке страницы** (1 раз)
|
||
- Пользователь открывает форму
|
||
- Можно загрузить из PostgreSQL (10 мс) - не критично
|
||
|
||
2. **При переходах между шагами** (редко)
|
||
- Пользователь нажимает "Далее"
|
||
- Можно загрузить из PostgreSQL (10 мс) - не критично
|
||
|
||
3. **При обновлении данных** (редко)
|
||
- Пользователь заполняет форму
|
||
- Сохраняется в PostgreSQL
|
||
|
||
### Вывод:
|
||
- ❌ **НЕ критично по скорости** - пользователь не заметит разницу
|
||
- ✅ **Важнее консистентность** - данные всегда актуальные
|
||
- ✅ **Проще архитектура** - один источник истины
|
||
|
||
---
|
||
|
||
## Компромиссное решение
|
||
|
||
### Вариант: Кеширование в Redis с инвалидацией
|
||
|
||
```python
|
||
# При чтении данных заявки
|
||
async def get_claim(claim_id: str):
|
||
# 1. Пробуем Redis (быстро)
|
||
cached = await redis.get(f"claim:{claim_id}")
|
||
if cached:
|
||
return json.loads(cached)
|
||
|
||
# 2. Если нет в кеше - из PostgreSQL
|
||
claim = await db.get_claim(claim_id)
|
||
|
||
# 3. Сохраняем в кеш на 1 час
|
||
await redis.set(f"claim:{claim_id}", json.dumps(claim), ttl=3600)
|
||
|
||
return claim
|
||
|
||
# При обновлении данных
|
||
async def update_claim(claim_id: str, data: dict):
|
||
# 1. Обновляем PostgreSQL
|
||
await db.update_claim(claim_id, data)
|
||
|
||
# 2. Инвалидируем кеш (удаляем из Redis)
|
||
await redis.delete(f"claim:{claim_id}")
|
||
|
||
# Или обновляем кеш сразу
|
||
await redis.set(f"claim:{claim_id}", json.dumps(data), ttl=3600)
|
||
```
|
||
|
||
### Плюсы:
|
||
- ✅ Быстрый доступ (если есть в кеше)
|
||
- ✅ Актуальные данные (инвалидация при обновлении)
|
||
- ✅ Fallback на PostgreSQL (если кеш пуст)
|
||
|
||
### Минусы:
|
||
- ❌ Дополнительная сложность
|
||
- ❌ Нужно инвалидировать кеш при каждом обновлении
|
||
- ❌ Риск устаревших данных (если забыли инвалидировать)
|
||
|
||
---
|
||
|
||
## Рекомендация для веб-формы
|
||
|
||
### Вариант 1: Только PostgreSQL (рекомендую)
|
||
|
||
**Когда использовать:**
|
||
- Данные читаются не так часто (загрузка страницы, переходы)
|
||
- Важна консистентность
|
||
- Простота архитектуры важнее скорости
|
||
|
||
**Плюсы:**
|
||
- ✅ Просто (один источник данных)
|
||
- ✅ Всегда актуальные данные
|
||
- ✅ Нет рассинхронизации
|
||
- ✅ PostgreSQL с индексами всё равно быстро (1-10 мс)
|
||
|
||
**Минусы:**
|
||
- ❌ Чуть медленнее, чем Redis (но не критично)
|
||
|
||
---
|
||
|
||
### Вариант 2: PostgreSQL + Redis кеш (если нужна скорость)
|
||
|
||
**Когда использовать:**
|
||
- Очень частые чтения (каждый запрос)
|
||
- Критична скорость (но для веб-формы это не так)
|
||
|
||
**Плюсы:**
|
||
- ✅ Быстрый доступ (0.1-1 мс)
|
||
- ✅ Меньше нагрузки на PostgreSQL
|
||
|
||
**Минусы:**
|
||
- ❌ Сложнее (нужна инвалидация кеша)
|
||
- ❌ Риск устаревших данных
|
||
- ❌ Больше кода для поддержки
|
||
|
||
---
|
||
|
||
## Итог
|
||
|
||
### Для веб-формы:
|
||
|
||
**Рекомендую: Только PostgreSQL**
|
||
|
||
**Почему:**
|
||
1. ⚡ PostgreSQL с индексами быстро (1-10 мс) - пользователь не заметит
|
||
2. ✅ Всегда актуальные данные (нет рассинхронизации)
|
||
3. ✅ Проще архитектура (один источник истины)
|
||
4. ✅ Данные читаются не так часто (не каждый запрос)
|
||
|
||
**Redis используй только для:**
|
||
- ✅ Pub/Sub (`ocr_events:{claim_id}`) - события в реальном времени
|
||
- ✅ Кеширование AI ответов (классификация, визарды) - если нужно
|
||
- ✅ SMS коды, временные токены - с TTL
|
||
|
||
**НЕ используй Redis для:**
|
||
- ❌ Основных данных заявки (есть в PostgreSQL)
|
||
- ❌ Документов (есть в PostgreSQL)
|
||
- ❌ Ответов визарда (есть в PostgreSQL)
|
||
|
||
---
|
||
|
||
## Если всё-таки нужен Redis кеш
|
||
|
||
Можно добавить опциональное кеширование:
|
||
|
||
```python
|
||
# В n8n workflow после claimsave
|
||
if (channel === 'web_form' && enable_cache === true) {
|
||
// Опционально: кешируем в Redis на 1 час
|
||
await redis.set(
|
||
`claim:${claim_id}`,
|
||
JSON.stringify(claim_data),
|
||
ttl=3600
|
||
);
|
||
}
|
||
```
|
||
|
||
Но это опционально и не обязательно для веб-формы.
|
||
|
||
|
||
|