Files
vesti/openspec/changes/archive/2026-09-16-fix-media-mount/proposal.md
T

69 lines
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Why
Пост #1017 (linux) опубликован без картинки: в Telegram ушёл только текст, хотя
у поста есть медиа (`media_path='media/linux_education_2772.jpg'`, файл на хосте
`/opt/vesti/media/linux_education_2772.jpg`, 151 КБ).
Причина: Docker-контейнер `vesti-publisher` монтирует
`../../media/media:/srv/publisher/media` — **внутренний** каталог `media/media/`.
С 2026-09-12 краулер качает медиа в `media/<file>` (внешний каталог), а не в
`media/media/<file>`. В контейнере (CWD `/srv/publisher`) путь `media/<file>`
резолвится в `/srv/publisher/media/<file>` = `/opt/vesti/media/media/<file>`,
которого для новых постов не существует.
В publisher (`services/publisher/app/main.py`):
```python
if req.card.media and Path(req.card.media).exists():
```
проверка проваливается → медиа молча пропускается, публикуется только текст.
Ошибки нет — файл «просто не найден».
Проверено в контейнере:
```
docker exec vesti-publisher python -c "import os; print(os.path.exists('media/linux_education_2772.jpg'))" # False
```
Затронуты все посты с медиа, скачанные с 2026-09-12 (новая раскладка). Старых
файлов в `media/media/` на диске нет (545 постов со старым путём вообще без
файлов — отдельная проблема, не этого change).
## What Changes
1. **`services/publisher/docker-compose.yml`**: монтировать весь каталог медиа
`../../media:/srv/publisher/media:ro` вместо `../../media/media`. Тогда в
контейнере видны ОБЕ раскладки:
- новые файлы: `/srv/publisher/media/<file>` = `media/<file>` ✓
- старые (если появятся/восстановятся): `/srv/publisher/media/media/<file>` = `media/media/<file>` ✓
2. **`services/publisher/app/main.py`**: устойчивый резолвинг медиа-файла в
контейнере. Вместо единственной проверки `Path(card.media).exists()` —
пробовать кандидатов в порядке приоритета (под контейнерный CWD):
- `card.media` как есть (заданный путь, напр. `media/<file>`,
резолвится от `/srv/publisher`),
- `media/<basename>` (если путь в БД содержал подкаталог),
- `media/media/<basename>` (старая раскладка).
Первый существующий путь идёт в `send_media`.
Это чинит и будущие случаи, когда веб пришлёт нормализованный путь, и
старые посты, файлы которых восстановят.
3. **`publisher/card.py`** — не меняем (нормализация путей на стороне веба уже
работает, publisher получает `media='media/<file>'`).
## Why Not
- Не переносить файлы из `media/` в `media/media/` и не править 12 строк БД:
новая раскладка правильная, старую не размножаем.
- Не отключать проверку существования файла: у 545 старых постов файла нет,
publisher должен молча пропускать отсутствующее медиа, а не падать.
- Не менять `media_path` в БД: веб (route `/media/{filename}`, MEDIA_DIRS)
и читает оба каталога, и publisher после фикса тоже.
## Impact
- Файлы: `services/publisher/docker-compose.yml`, `services/publisher/app/main.py`.
- Сервис: пересоздать контейнер publisher (`docker compose up -d` — volume
меняется), проверить healthz.
- Данные: без миграций БД.
- Rollback: вернуть монтирование `../../media/media` и старый код, пересоздать
контейнер.