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

4.3 KiB
Raw Blame History

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):

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 и старый код, пересоздать контейнер.