From 0098e147ac7f3b3f1f695ba0bdbecc9b042adeba Mon Sep 17 00:00:00 2001 From: Andrey Date: Sun, 13 Sep 2026 09:16:19 +0300 Subject: [PATCH] =?UTF-8?q?:bug:=20fix(updates):=20=D0=B7=D0=B0=D0=BF?= =?UTF-8?q?=D1=83=D1=81=D0=BA=D0=B0=D1=82=D1=8C=20=D1=83=D1=81=D1=82=D0=B0?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2=D1=89=D0=B8=D0=BA,=20=D0=B0=20=D0=BD=D0=B5?= =?UTF-8?q?=20=D0=B2=D1=82=D0=BE=D1=80=D0=BE=D0=B9=20=D1=86=D0=B8=D0=BA?= =?UTF-8?q?=D0=BB=20=D0=BE=D0=B6=D0=B8=D0=B4=D0=B0=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Входная точка образа updater'а — сценарий ожидания запросов, поэтому `docker run ... chatballs-updater-apply.sh` не запускал установку, а передавал имя сценария аргументом в тот же цикл. Помощник поднимался без compose-меток, уходил в вечный sleep и никогда не дописывал статус: интерфейс крутил установку без конца, а новые запросы отбрасывались как «уже идёт». Та же ошибка была во втором вызове — копировании compose.yaml на хост. Обе команды теперь подменяют входную точку. Плюс страховка в цикле: если помощник исчез, не дописав результат, установка помечается неудачной. Co-Authored-By: Claude Opus 5 --- deploy/updater/chatballs-updater-apply.sh | 7 +++++-- deploy/updater/chatballs-updater.sh | 19 +++++++++++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/deploy/updater/chatballs-updater-apply.sh b/deploy/updater/chatballs-updater-apply.sh index e87d181..fe4e862 100644 --- a/deploy/updater/chatballs-updater-apply.sh +++ b/deploy/updater/chatballs-updater-apply.sh @@ -80,8 +80,11 @@ fi # Файл на хосте должен соответствовать работающей версии: иначе следующий # ручной `docker compose up` откатил бы установку. if [ -n "$WORKDIR" ]; then - if docker run --rm -v "$WORKDIR:/host" -v "$VOLUME:/updates" "$SELF_IMAGE" \ - sh -c "cp /updates/compose.$VERSION.yaml /host/compose.yaml" >>"$LOG" 2>&1; then + # Входную точку образа подменяем: иначе вместо копирования запустится цикл + # ожидания запросов, и контейнер никогда не завершится. + if docker run --rm --entrypoint /bin/sh \ + -v "$WORKDIR:/host" -v "$VOLUME:/updates" "$SELF_IMAGE" \ + -c "cp /updates/compose.$VERSION.yaml /host/compose.yaml" >>"$LOG" 2>&1; then log "compose.yaml в $WORKDIR обновлён" else log "предупреждение: не удалось обновить compose.yaml в $WORKDIR" diff --git a/deploy/updater/chatballs-updater.sh b/deploy/updater/chatballs-updater.sh index a55f414..dcf2ad6 100644 --- a/deploy/updater/chatballs-updater.sh +++ b/deploy/updater/chatballs-updater.sh @@ -61,8 +61,20 @@ if [ -z "$PROJECT" ] || [ -z "$UPDATES_VOLUME" ] || [ -z "$SELF_IMAGE" ]; then fi log "готов: проект $PROJECT, каталог ${WORKDIR:-?}, том $UPDATES_VOLUME" +helper_running() { + docker ps -q --filter "name=^chatballs-updater-apply$" | grep -q . +} + while true; do touch "$HEARTBEAT" + # Помощник мог исчезнуть, не дописав статус (падение, kill, нехватка памяти). + # Без этой проверки статус остался бы «running» навсегда: интерфейс крутил бы + # установку, а новые запросы отбрасывались бы как «уже идёт». + if [ -f "$STATUS" ] && [ "$(json_field "$STATUS" status)" = "running" ] && ! helper_running; then + stale_version="$(json_field "$STATUS" version)" + log "помощник завершился, не дописав результат установки $stale_version" + write_status failed "$stale_version" "installer stopped without result" + fi if [ -f "$REQUEST" ]; then version="$(json_field "$REQUEST" version)" compose_url="$(json_field "$REQUEST" compose_url)" @@ -76,7 +88,7 @@ while true; do write_status failed "$version" "compose.yaml address is not the release page" sleep "$POLL_SECONDS"; continue fi - if docker ps -q --filter "name=^chatballs-updater-apply$" | grep -q .; then + if helper_running; then log "установка уже идёт — запрос $version пропущен" sleep "$POLL_SECONDS"; continue fi @@ -84,7 +96,10 @@ while true; do write_status running "$version" "starting" # Помощник вне проекта: свой образ, docker.sock и тот же том; переживает # пересоздание этого сервиса и дописывает статус до конца. + # Входная точка образа — этот же сценарий, поэтому её обязательно подменить: + # иначе помощник вместо установки запустит второй цикл ожидания запросов. if ! docker run -d --rm --name chatballs-updater-apply \ + --entrypoint /bin/sh \ -e CHATBALLS_UPDATE_REPO="$REPO" \ -e CHATBALLS_PROJECT="$PROJECT" \ -e CHATBALLS_WORKDIR="$WORKDIR" \ @@ -92,7 +107,7 @@ while true; do -e CHATBALLS_UPDATER_IMAGE="$SELF_IMAGE" \ -v "$SOCKET:$SOCKET" \ -v "$UPDATES_VOLUME:$DIR" \ - "$SELF_IMAGE" chatballs-updater-apply.sh "$version" "$expected" >/dev/null 2>"$DIR/apply.err"; then + "$SELF_IMAGE" /usr/local/bin/chatballs-updater-apply.sh "$version" "$expected" >/dev/null 2>"$DIR/apply.err"; then write_status failed "$version" "could not start helper: $(cat "$DIR/apply.err" 2>/dev/null | tail -c 400)" fi fi