# Dev Report: Pagination Fix — commit per page + дедупликация

**Дата:** 2026-04-22  
**Статус:** DONE ✅  
**ТЗ:** TZ-fr24-worker-pagination-fix.md  
**Исполнитель:** subagent dev-pagination-fix

---

## Итог

Все изменения реализованы строго по ТЗ. Синтаксис проверен — ошибок нет.

---

## Изменения

### `config.py`
- Добавлено поле `MAX_PAGES: int = int(os.getenv("FR24_MAX_PAGES", "200"))`  
  Защитный лимит: 200 страниц × 20 = 4000 рейсов максимум.

### `fr24_worker.py`
1. **Удалена** функция `fetch_flight_summaries()` — накапливала все страницы в памяти, при ошибке всё терялось.

2. **Добавлен** генератор `iter_flight_summary_pages(target_date: date) -> Iterator[List[Dict]]`:
   - Возвращает страницы по одной (yield)
   - Дедупликация по `fr24_id` через `seen_fr24_ids: set` — убирает ×4 дубли от `both:SVO,both:DME,both:VKO,both:ZIA`
   - Ловит исключения на каждой странице (break с логом, не падает весь процесс)
   - Защитный лимит `config.MAX_PAGES` с предупреждением в лог
   - Debug-лог: page, offset, got, unique, total_seen

3. **Переписан** блок в `run()`:
   - Убран блок `try: summaries = fetch_flight_summaries(...)` 
   - Итерация через `for page in iter_flight_summary_pages(target_date):`
   - `stats["flights_found"] += len(page)` — инкрементальный счётчик
   - После обработки каждой страницы — `conn.commit()` с логом
   - При ошибке commit — `conn.rollback()` + `stats["errors"] += 1`
   - Индивидуальные `conn.commit()` per-flight убраны (остался только per-page)

---

## Проверка синтаксиса

```
$ python3 -m py_compile config.py && echo OK
config.py OK

$ python3 -m py_compile fr24_worker.py && echo OK
fr24_worker.py OK
```

---

## Следующий шаг (деплой)

```bash
docker cp ingest/tracks_fr24/fr24_worker.py fr24-ingest:/app/ingest/tracks_fr24/fr24_worker.py
docker cp ingest/tracks_fr24/config.py      fr24-ingest:/app/ingest/tracks_fr24/config.py
```

Проверка:
```
POST http://fr24-vm:8001/run?date=2026-04-19
```
Должны появляться строки в `flight_actual` постепенно, не ждать конца всей загрузки.
