Telemax/update.sh
Folist 06921ca69b Защита от двойного запуска обновления по кнопке «Обновить»
Пока обновление идёт (сборка+рестарт — несколько минут), свежий /version
всё ещё показывает живую кнопку «Обновить» (контейнер ещё не пересобран,
выглядит устаревшим), и повторное нажатие ставило второй маркер → вотчер
на следующем тике запускал второй update.sh поверх идущего.

- update-watcher.sh: flock -n — параллельный запуск невозможен, поздний тик
  тихо выходит (маркер всё равно поглощается).
- update.sh: пишет data/update-in-progress на время работы (trap EXIT
  очищает при любом исходе, включая краш).
- Кнопка tlmx_update: проверяет оба маркера (queued / in-progress) и вместо
  второго запроса отвечает «обновление уже идёт».
2026-08-15 16:16:17 +03:00

83 lines
3.7 KiB
Bash
Executable file

#!/usr/bin/env bash
# Pulls the latest main, rebuilds and restarts the container. Normally run
# automatically by update-watcher.sh (via the telemax-updater systemd timer,
# see setup.sh) after the bot's /version "Обновить" button — safe to run by
# hand too if you'd rather update on your own schedule.
set -euo pipefail
cd "$(dirname "$0")"
# .env isn't loaded into this shell's own environment (docker's env_file: only
# injects it into the container) — read TELEGRAM_BOT_TOKEN/TARGET_TELEGRAM_GROUP
# ourselves so progress can be reported even while the bot itself is the thing
# being replaced.
set -a
# shellcheck disable=SC1091
[ -f .env ] && source .env
set +a
# Installs set up before setup.sh started restricting .env permissions left it
# world-readable — tighten it on every update so old installs get fixed too.
[ -f .env ] && chmod 600 .env
# In-progress flag the container can see (data/ is mounted at /app/.data): the bot's
# "Обновить" button reads it to refuse a second request while one is already running.
# Cleared on ANY exit (success, failure, or crash) so it never gets stuck.
mkdir -p data
touch data/update-in-progress
trap 'rm -f data/update-in-progress' EXIT
notify() {
[ -n "${TELEGRAM_BOT_TOKEN:-}" ] && [ -n "${TARGET_TELEGRAM_GROUP:-}" ] || return 0
curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
-d "chat_id=${TARGET_TELEGRAM_GROUP}" --data-urlencode "text=$1" >/dev/null 2>&1 || true
}
STEP="старт"
on_error() {
notify "❌ Обновление не удалось на шаге «${STEP}» — мост продолжает работать на прежней версии. Подробности: cat $(pwd)/data/update.log"
}
trap on_error ERR
notify "🔄 Начинаю обновление..."
STEP="git pull"
echo "[update] $(date -u +%Y-%m-%dT%H:%M:%SZ) pulling latest main..."
git pull --ff-only
# Written before the rebuild/restart so the NEW container's own startup can
# read it and report back in Telegram (app.ts's reportIfJustUpdated) — just
# needs to exist by the time the new process boots. `data/`, NOT `.data/` —
# that's the container-internal path; docker-compose.yml mounts host `./data`
# there, and these scripts run on the host, not in the container (mixed the
# two up originally, which silently broke the whole watcher — confirmed live
# 2026-08-14: a marker written straight to `data/` was never picked up
# because update-watcher.sh was checking `.data/` instead).
mkdir -p data
git rev-parse HEAD > data/update-completed
STEP="сборка образа"
echo "[update] building (GIT_COMMIT=$(git rev-parse --short HEAD))..."
GIT_COMMIT=$(git rev-parse HEAD) docker compose build
STEP="перезапуск контейнера"
echo "[update] restarting..."
docker compose up -d
STEP="проверка после запуска"
sleep 5
if [ -z "$(docker compose ps --status running --format '{{.Name}}' 2>/dev/null)" ]; then
rm -f data/update-completed
notify "❌ Контейнер не поднялся после обновления — проверьте: docker compose logs"
exit 1
fi
# Every rebuild retags `latest` onto the new image, leaving the previous one
# (the biggest chunk of disk churn per update — this image is ~2GB, mostly
# Chromium for sticker rendering) dangling. `image prune -f` only removes
# dangling/untagged images, never anything still referenced or cached for the
# next build — NOT `-a`/`system prune`, which strips the build cache too and
# makes every future rebuild slow again from scratch (hit that live 2026-08-14).
echo "[update] cleaning up dangling images..."
docker image prune -f >/dev/null 2>&1 || true
echo "[update] done."