47 lines
3.5 KiB
Markdown
47 lines
3.5 KiB
Markdown
# 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` покажет «=» (пропуски). |