Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 1 addition & 26 deletions scripts/deploy-selfhost-image.sh
Original file line number Diff line number Diff line change
Expand Up @@ -61,31 +61,6 @@ validate_inputs() {
fi
}

wait_for_healthy() {
local deadline container_id status

deadline=$((SECONDS + HEALTH_TIMEOUT_SECONDS))
while [ "$SECONDS" -le "$deadline" ]; do
container_id="$(docker compose "${compose_args[@]}" ps -q "$SERVICE" 2>/dev/null || true)"
if [ -n "$container_id" ]; then
status="$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' "$container_id" 2>/dev/null || true)"
if [ "$status" = "healthy" ]; then
echo "selfhost image deploy: $SERVICE is healthy"
return 0
fi
fi
if [ "$SECONDS" -ge "$deadline" ]; then
break
fi
sleep 2
done

echo "error: $SERVICE did not become healthy within ${HEALTH_TIMEOUT_SECONDS}s" >&2
docker compose "${compose_args[@]}" ps "$SERVICE" >&2 || true
docker compose "${compose_args[@]}" logs --tail=80 "$SERVICE" >&2 || true
exit 1
}

require_cmd docker
docker compose version >/dev/null

Expand Down Expand Up @@ -126,7 +101,7 @@ docker compose "${compose_args[@]}" pull --policy always "$SERVICE"
echo "selfhost image deploy: restarting $SERVICE"
maybe_infisical_run docker compose "${compose_args[@]}" up -d --no-build --no-deps "$SERVICE"

wait_for_healthy
wait_for_healthy "$SERVICE" "$HEALTH_TIMEOUT_SECONDS" "selfhost image deploy" "${compose_args[@]}"
env_put LOOPOVER_IMAGE "$IMAGE"

echo "selfhost image deploy: complete ($IMAGE)"
10 changes: 10 additions & 0 deletions scripts/deploy-selfhost-prebuilt.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ set -euo pipefail
ENV_FILE="${SELFHOST_ENV_FILE:-.env}"
NODE_IMAGE="${SELFHOST_NODE_IMAGE:-public.ecr.aws/docker/library/node:24-slim}"
SERVICE="${SELFHOST_SERVICE:-loopover}"
# #8395: same override + default deploy-selfhost-image.sh already uses, so both deploy paths honour one
# health-check budget.
HEALTH_TIMEOUT_SECONDS="${SELFHOST_HEALTH_TIMEOUT_SECONDS:-180}"
SKIP_SENTRY_UPLOAD="${SELFHOST_SKIP_SENTRY_UPLOAD:-0}"
SENTRY_CLI_PACKAGE="${SENTRY_CLI_PACKAGE:-@sentry/cli@3.6.0}"

Expand Down Expand Up @@ -118,6 +121,13 @@ YAML

echo "selfhost deploy: restarting $SERVICE"
maybe_infisical_run docker compose "${compose_args[@]}" up -d --no-deps "$SERVICE"

# #8395: `up -d` only confirms the container was CREATED and STARTED -- without this, a crash-looping
# or never-healthy image still reported "selfhost deploy: complete". Called here (not at the top level)
# because compose_args is function-local, and it includes the generated override file. Exits non-zero
# with the same ps/logs diagnostics deploy-selfhost-image.sh produces; the EXIT trap above still cleans
# up the temp override file on that path.
wait_for_healthy "$SERVICE" "$HEALTH_TIMEOUT_SECONDS" "selfhost deploy" "${compose_args[@]}"
}

require_cmd docker
Expand Down
35 changes: 35 additions & 0 deletions scripts/lib/selfhost-deploy-common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,38 @@ compose_file_args() {
printf '%s\n' -f "$file"
done
}

# Block until $service reports healthy, or fail the deploy (#8395). Moved here from
# deploy-selfhost-image.sh so BOTH deploy scripts share one implementation instead of one hand-copying
# the other -- deploy-selfhost-prebuilt.sh previously printed "complete" straight after
# `docker compose up -d`, which only confirms the container STARTED, so a crash-looping image reported
# success. Parameterized rather than reading caller globals: prebuilt's compose_args is a function-local
# array. $log_prefix keeps each script's existing message wording byte-identical.
# Usage: wait_for_healthy <service> <timeout_seconds> <log_prefix> <compose_args...>
wait_for_healthy() {
local service="$1" timeout_seconds="$2" log_prefix="$3"
shift 3
local -a compose_args=("$@")
local deadline container_id status

deadline=$((SECONDS + timeout_seconds))
while [ "$SECONDS" -le "$deadline" ]; do
container_id="$(docker compose "${compose_args[@]}" ps -q "$service" 2>/dev/null || true)"
if [ -n "$container_id" ]; then
status="$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' "$container_id" 2>/dev/null || true)"
if [ "$status" = "healthy" ]; then
echo "$log_prefix: $service is healthy"
return 0
fi
fi
if [ "$SECONDS" -ge "$deadline" ]; then
break
fi
sleep 2
done

echo "error: $service did not become healthy within ${timeout_seconds}s" >&2
docker compose "${compose_args[@]}" ps "$service" >&2 || true
docker compose "${compose_args[@]}" logs --tail=80 "$service" >&2 || true
exit 1
}