#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" # shellcheck disable=SC1091 source "$SCRIPT_DIR/common.sh" load_local_env wait_for_docker APP_SERVICES=( auth gateway wallet other live order console scheduling external visual-monitor golang ) INFRA_SERVICES=( mysql redis mongo nacos zookeeper ) if ! local_rocketmq_disabled; then INFRA_SERVICES+=( rocketmq-namesrv rocketmq-broker rocketmq-proxy ) fi FAILURES=0 container_name_for_service() { case "$1" in visual-monitor) printf '%s\n' "chatapp3-local-visual-monitor" ;; rocketmq-namesrv) printf '%s\n' "chatapp3-local-rocketmq-namesrv" ;; rocketmq-broker) printf '%s\n' "chatapp3-local-rocketmq-broker" ;; rocketmq-proxy) printf '%s\n' "chatapp3-local-rocketmq-proxy" ;; *) printf '%s\n' "chatapp3-local-$1" ;; esac } health_url_for_service() { local service="$1" case "$service" in gateway) printf 'http://127.0.0.1:%s/actuator/health\n' "$(service_port "$service")" ;; console) printf 'http://127.0.0.1:%s/console/actuator/health\n' "$(service_port "$service")" ;; golang) printf 'http://127.0.0.1:%s/health\n' "$(service_port "$service")" ;; *) printf 'http://127.0.0.1:%s/actuator/health\n' "$(service_port "$service")" ;; esac } http_probe() { local url="$1" local body_file http_code body_file="$(mktemp)" http_code="$(curl -sS --max-time 5 -o "$body_file" -w '%{http_code}' "$url" || true)" printf '%s\n' "$http_code" cat "$body_file" rm -f "$body_file" } print_row() { printf '%-16s %-10s %-12s %s\n' "$1" "$2" "$3" "$4" } published_host_port() { local container_name="$1" local target_port="$2" docker port "$container_name" "$target_port" 2>/dev/null | sed -n '1s/.*://p' } probe_app_service() { local service="$1" local container_name container_state health_url local probe_payload http_code body status detail container_name="$(container_name_for_service "$service")" container_state="$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' "$container_name" 2>/dev/null || printf 'missing')" health_url="$(health_url_for_service "$service")" probe_payload="$(http_probe "$health_url")" http_code="$(printf '%s\n' "$probe_payload" | sed -n '1p')" body="$(printf '%s\n' "$probe_payload" | sed '1d')" status="FAIL" detail="container=${container_state} http=${http_code}" if [ "$http_code" = "200" ]; then if [ "$service" = "golang" ]; then status="OK" detail="container=${container_state} http=200 path=/health" else local actuator_status reason actuator_status="$(printf '%s' "$body" | jq -r '.status // empty' 2>/dev/null || true)" if [ "$actuator_status" = "UP" ]; then status="OK" detail="container=${container_state} actuator=UP" else reason="$(printf '%s' "$body" | jq -r '.components.refreshScope.details.error // .components.db.details.error // .error // empty' 2>/dev/null || true)" detail="container=${container_state} actuator=${actuator_status:-unknown}" if [ -n "$reason" ]; then detail="$detail reason=$(printf '%s' "$reason" | tr '\n' ' ' | cut -c1-120)" fi fi fi else local reason reason="$(printf '%s' "$body" | jq -r '.errorMsg // .message // .status // empty' 2>/dev/null || true)" if [ -n "$reason" ]; then detail="$detail reason=$(printf '%s' "$reason" | tr '\n' ' ' | cut -c1-120)" fi fi if [ "$status" != "OK" ]; then FAILURES=$((FAILURES + 1)) fi print_row "$service" "$status" "$container_state" "$detail" } probe_infra_service() { local service="$1" local container_name container_state status detail container_name="$(container_name_for_service "$service")" container_state="$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' "$container_name" 2>/dev/null || printf 'missing')" status="FAIL" detail="container=${container_state}" case "$service" in nacos) local probe_payload http_code body nacos_status probe_payload="$(http_probe "http://127.0.0.1:${LIKEI_LOCAL_NACOS_PORT}/nacos/actuator/health")" http_code="$(printf '%s\n' "$probe_payload" | sed -n '1p')" body="$(printf '%s\n' "$probe_payload" | sed '1d')" nacos_status="$(printf '%s' "$body" | jq -r '.status // empty' 2>/dev/null || true)" if [ "$http_code" = "200" ] && [ "$nacos_status" = "UP" ]; then status="OK" detail="container=${container_state} actuator=UP" else detail="container=${container_state} http=${http_code} actuator=${nacos_status:-unknown}" fi ;; zookeeper) local zk_host_port zk_host_port="$(published_host_port "$container_name" "2181/tcp")" if [ -z "$zk_host_port" ]; then zk_host_port="${LIKEI_LOCAL_ZOOKEEPER_EXPOSE_PORT}" fi if nc -z 127.0.0.1 "$zk_host_port" >/dev/null 2>&1; then status="OK" detail="container=${container_state} tcp=open port=${zk_host_port}" else detail="container=${container_state} tcp=not_ready port=${zk_host_port}" fi ;; rocketmq-namesrv) if nc -z 127.0.0.1 "${LIKEI_LOCAL_ROCKETMQ_NAMESRV_PORT}" >/dev/null 2>&1; then status="OK" detail="container=${container_state} tcp=open port=${LIKEI_LOCAL_ROCKETMQ_NAMESRV_PORT}" else detail="container=${container_state} tcp=not_ready port=${LIKEI_LOCAL_ROCKETMQ_NAMESRV_PORT}" fi ;; rocketmq-broker) if docker exec chatapp3-local-rocketmq-broker sh mqadmin clusterList -n rocketmq-namesrv:9876 2>/dev/null | grep -q "DefaultCluster"; then status="OK" detail="container=${container_state} cluster=DefaultCluster" else detail="container=${container_state} cluster=not_ready" fi ;; rocketmq-proxy) if nc -z 127.0.0.1 "${LIKEI_LOCAL_ROCKETMQ_PROXY_GRPC_PORT}" >/dev/null 2>&1; then status="OK" detail="container=${container_state} tcp=open port=${LIKEI_LOCAL_ROCKETMQ_PROXY_GRPC_PORT}" else detail="container=${container_state} tcp=not_ready port=${LIKEI_LOCAL_ROCKETMQ_PROXY_GRPC_PORT}" fi ;; *) if [ "$container_state" = "healthy" ] || [ "$container_state" = "running" ]; then status="OK" detail="container=${container_state}" fi ;; esac if [ "$status" != "OK" ]; then FAILURES=$((FAILURES + 1)) fi print_row "$service" "$status" "$container_state" "$detail" } echo "App Services" print_row "SERVICE" "RESULT" "CONTAINER" "DETAIL" for service in "${APP_SERVICES[@]}"; do probe_app_service "$service" done echo echo "Infra Services" print_row "SERVICE" "RESULT" "CONTAINER" "DETAIL" for service in "${INFRA_SERVICES[@]}"; do probe_infra_service "$service" done echo if [ "$FAILURES" -eq 0 ]; then echo "SUMMARY: all checked local backend services are healthy" else echo "SUMMARY: $FAILURES service(s) need attention" exit 1 fi