Files
dedinit.ru/openspec/changes/deploy-sftp-incremental/design.md
T

3.5 KiB
Raw Blame History

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

Подход

Модифицируем единственный файл tools/deploy_sftp.py:

  1. Сравнение файлов (size + mtime):

    • Для каждого локального файла вызываем sftp.stat(remote_path).
    • Если stat успешен И (st_size, int(st_mtime)) совпадает с локальным (os.stat(lpath).st_size, int(os.stat(lpath).st_mtime)) — пропускаем (не льём).
    • Если stat бросает IOError (нет файла) или не совпадает — заливаем.
    • Метрику печатаем: = пропущено, + залито.
  2. Таймауты против зависания:

    • paramiko.Transport создаём с banner_timeout=30, timeout=30.
    • Для каждого put используем paramiko окно: оборачиваем в socket.setdefaulttimeout(120) (SFTP-канал унаследует) — если операция длится дольше 2 мин, канал падает с ошибкой, скрипт падает с понятным сообщением вместо бесконечного висения.
    • Удаление тоже не должно висеть: те же таймауты.
  3. Что НЕ меняется:

    • Mirror-логика (всё, чего нет локально, удаляется) — сохранена.
    • Рекурсивное создание каталогов — сохранено.
    • Интерфейс: tools/deploy_sftp.py [--dry-run], переменные DEDINIT_* / SSHPASS.
    • Вызов из .gitea/workflows/deploy.yml не меняется.

Риски

  • mtime на сервере (Jino) может отличаться от локального (часовой пояс, точность). SFTP stat возвращает mtime в секундах; локально int(st_mtime) — тоже секунды. Допуск: считаем «не изменился», если |remote_mtime - local_mtime| <= 120 И размеры равны. (Больше 2 мин расхождения не бывает при честном сравнении; зато гарантируем, что файл, записанный «только что» локально и залитый минуту назад, не перельётся без нужды.) Решение: допуск на mtime = 300 сек (5 мин) при равенстве размеров.

  • Ложные пропуски: если сервер отдаёт mtime 0 (некоторые SFTP-сервера) — считаем файл изменённым (льём всегда). Проверка if remote_mtime > 0.

  • Большой дерево: rlist рекурсивно обходит всё дерево — оставляем как есть (работает, это доли секунды на 500 файлов).

Верификация

  • python3 tools/deploy_sftp.py --dry-run локально: показывает список изменившихся (должно быть 0 после сборки в тот же public/... фактически покажет все «+», т.к. на сервере старый mtime — это ок, первый деплой льёт всё).
  • После первого инкрементального деплоя повторный --dry-run покажет «=» (пропуски).