Files

3.5 KiB
Raw Permalink Blame History

Design: Инкрементальный SFTP-деплой

Проблема

tools/deploy_sftp.py mirror-заливал ВСЕ 524 файла (66M) каждый деплой, включая неизменные тяжёлые (21M PDF, 11M×2 M4V) — деплой занимал ~36 мин (замер №1: run создан 16:54:19Z → прод виден 17:30:20Z). Плюс: при обрыве SFTP-соединения скрипт вис бесконечно (нет таймаутов) — оба раза висел на 2026/gotosocial-relay-match-by-default/hero.svg.

Решение

Единственный файл tools/deploy_sftp.py:

  1. Инкремент по (size + SHA1): для каждого локального файла — sftp.stat(); если удалённый существует и (размер совпадает И SHA1 содержимого совпадает) — пропуск; иначе sftp.put().

    • mtime НЕ используется: в CI (Gitea Actions) checkout ставит свежий mtime всем файлам → mtime-сравнение бесполезно.
    • SHA1 читается потоково с удалённого через sftp.open() (1MB чанками) — корректно для 21M PDF (несколько секунд).
    • Для несовпадающих размеров хэш не считается (быстрый путь).
  2. Защита от зависаний:

    • Transport.set_keepalive(15) — пинги; мёртвое соединение падает само.
    • sftp.get_channel().settimeout(120) — операция дольше 120с прерывается.
    • with_retry() — при исключении переподключение (до 3 попыток, sleep 2с), put/remove повторяются; после исчерпания — выход с ненулевым кодом.
  3. Mirror-удаление сохранено: remote_files - local_files → remove().

  4. CI: python3-paramiko ставится через apt (не pip в venv) — не зависит от PyPI, быстрее (установка случайно занимала 15-20 мин).

Почему не mtime

В Gitea Actions actions/checkout распаковывает репозиторий с текущим mtime → все файлы «свежие» относительно сервера → mtime-сравнение никогда не пропускает. SHA1 — единственный надёжный индикатор неизменности для CI.

Альтернативы, отклонённые

  • rsync: Jino SFTP-only, удалённый exec запрещён.
  • Манифест (JSON) прошлого деплоя: усложняет, требует хранения состояния; SHA1-сравнение с сервером самодостаточно.
  • Только размер: риск ложного пропуска при изменении содержимого без смены размера (маловероятно для статики, но SHA1 дешевле ошибки).

Открытые вопросы

  • Точное время залива (замер №2) зависит от пропускной способности Jino SFTP.
  • SHA1 крупных файлов при каждом деплое: 21M PDF → ~2-5с на чтение с сервера; приемлемо по сравнению с перезаливкой.