#!/bin/sh set -eu ROOT=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd) ENV_FILE="$ROOT/.env.load" REPLICAS=${1:-} "$ROOT/scripts/ensure-local-load-env.sh" set -a # shellcheck source=/dev/null . "$ENV_FILE" set +a : "${LOAD_PROJECT:?LOAD_PROJECT is missing from .env.load}" : "${LOAD_HOST:?LOAD_HOST is missing from .env.load}" : "${LOAD_WEB_REPLICAS:?LOAD_WEB_REPLICAS is missing from .env.load}" : "${LOAD_WORKER_REPLICAS:?LOAD_WORKER_REPLICAS is missing from .env.load}" if [ "$LOAD_PROJECT" = who_need_help ]; then echo "The load profile must not use the staging Compose project." >&2 exit 1 fi if [ -n "$REPLICAS" ]; then LOAD_WEB_REPLICAS=$REPLICAS fi case "$LOAD_WEB_REPLICAS:$LOAD_WORKER_REPLICAS" in *[!0-9:]* | 0:* | *:0 | :* | *:) echo "Web and worker replica counts must be positive integers." >&2 exit 1 ;; esac cd "$ROOT" compose() { docker compose \ --env-file "$ENV_FILE" \ -p "$LOAD_PROJECT" \ -f compose.yaml \ -f compose.load.yaml \ "$@" } cleanup_failed_start() { status=$? trap - EXIT HUP INT TERM if [ "$status" -ne 0 ]; then # A cancelled Docker API request can finish creating a network just after # the first `compose down`. Repeat the exact project-scoped teardown until # the project has no containers or networks, or the bounded retry expires. attempt=0 while [ "$attempt" -lt 5 ]; do compose down --remove-orphans >/dev/null 2>&1 || true remaining_containers=$(docker ps -aq \ --filter "label=com.docker.compose.project=$LOAD_PROJECT") remaining_networks=$(docker network ls -q \ --filter "label=com.docker.compose.project=$LOAD_PROJECT") if [ -z "$remaining_containers" ] && [ -z "$remaining_networks" ]; then break fi attempt=$((attempt + 1)) sleep 1 done if image_id=$(docker image inspect --format '{{.Id}}' who-need-help:load-tools 2>/dev/null); then if [ -z "$(docker ps -aq --filter "ancestor=$image_id")" ]; then docker image rm who-need-help:load-tools >/dev/null 2>&1 || true fi fi if [ -n "$(docker ps -aq --filter "label=com.docker.compose.project=$LOAD_PROJECT")" ] || \ [ -n "$(docker network ls -q --filter "label=com.docker.compose.project=$LOAD_PROJECT")" ]; then echo "Load-profile startup cleanup left project resources behind." >&2 status=1 fi fi exit "$status" } trap cleanup_failed_start EXIT HUP INT TERM docker build --target load_tools --tag who-need-help:load-tools . compose up -d --build --wait \ --scale "web=$LOAD_WEB_REPLICAS" \ --scale "worker=$LOAD_WORKER_REPLICAS" COMPOSE_PROJECT_NAME=$LOAD_PROJECT "$ROOT/scripts/verify-realtime-cluster.sh" compose COMPOSE_PROJECT_NAME=$LOAD_PROJECT "$ROOT/scripts/verify-beam-runtime.sh" compose status=$( curl --silent --show-error \ --header "Host: $LOAD_HOST" \ --output /dev/null \ --write-out '%{http_code}' \ "http://localhost:$HTTP_PORT/healthz/ready" ) if [ "$status" != 200 ]; then echo "Load-profile readiness returned HTTP $status instead of 200." >&2 exit 1 fi curl --fail --silent --show-error \ --header "Host: $LOAD_HOST" \ "http://localhost:$HTTP_PORT/healthz/ready" printf '\nLoad profile is ready with %s web and %s worker replicas.\n' \ "$LOAD_WEB_REPLICAS" "$LOAD_WORKER_REPLICAS" trap - EXIT HUP INT TERM