345529cde0
Безопасный коммит незакоммиченной работы перед реализацией бронирования слотов. Вне коммита оставлены: package-lock.json (пустой, мусор), requests.json (scratch-данные).
539 lines
14 KiB
Bash
Executable File
539 lines
14 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
repo_root="$(cd "$script_dir/../.." && pwd)"
|
|
local_bundle_dir="$repo_root/deploy/local-bundle"
|
|
compose_file="$local_bundle_dir/docker-compose.yml"
|
|
local_bundle_env_file="$local_bundle_dir/.env"
|
|
|
|
if [[ -f "$local_bundle_env_file" ]]; then
|
|
set -a
|
|
# shellcheck disable=SC1090
|
|
source "$local_bundle_env_file"
|
|
set +a
|
|
fi
|
|
|
|
config_repo_dir="${CONFIG_REPO_DIR:-$repo_root/config-repo}"
|
|
runtime_dir="${LOCAL_JAR_RUNTIME_DIR:-$repo_root/build/local-jar-runtime}"
|
|
pid_dir="$runtime_dir/pids"
|
|
log_dir="$runtime_dir/logs"
|
|
|
|
if [[ "$config_repo_dir" != /* ]]; then
|
|
config_repo_dir="$repo_root/$config_repo_dir"
|
|
fi
|
|
|
|
if [[ "$runtime_dir" != /* ]]; then
|
|
runtime_dir="$repo_root/$runtime_dir"
|
|
pid_dir="$runtime_dir/pids"
|
|
log_dir="$runtime_dir/logs"
|
|
fi
|
|
|
|
config_service="spring-cloud-config-server"
|
|
app_services=(
|
|
pcp-srpring-boot-admin-server
|
|
pcp-stations-service
|
|
pcp-satellite-catalog-service
|
|
pcp-request-service
|
|
pcp-route-processing-service
|
|
pcp-ballistics-service
|
|
slots-service
|
|
pcp-complex-mission-service
|
|
pcp-mission-planing-service
|
|
pcp-coverage-scheme-service
|
|
pcp-dynamic-plan-service
|
|
tle-monitoring-service
|
|
pcp-tgu-service
|
|
pcp-ui-service
|
|
)
|
|
all_services=("$config_service" "${app_services[@]}")
|
|
|
|
databases=(
|
|
pcp_ballistics
|
|
pcp_requests
|
|
pcp_route_processing
|
|
pcp_missions
|
|
pcp_slots
|
|
pcp_complex_plan
|
|
pcp_satellite_catalog
|
|
pcp_stations
|
|
pcp_tgu
|
|
pcp_tle
|
|
pcp_satellites
|
|
)
|
|
|
|
declare -A service_ports=(
|
|
[spring-cloud-config-server]="${CONFIG_SERVER_PORT:-38888}"
|
|
[pcp-srpring-boot-admin-server]="${PCP_ADMIN_PORT:-7000}"
|
|
[tle-monitoring-service]="${PCP_TLE_MONITORING_PORT:-7001}"
|
|
[pcp-complex-mission-service]="${PCP_COMPLEX_MISSION_PORT:-7002}"
|
|
[pcp-ballistics-service]="${PCP_BALLISTICS_PORT:-7003}"
|
|
[pcp-route-processing-service]="${PCP_ROUTE_PROCESSING_PORT:-7004}"
|
|
[pcp-request-service]="${PCP_REQUEST_PORT:-7005}"
|
|
[slots-service]="${PCP_SLOTS_PORT:-7006}"
|
|
[pcp-ui-service]="${PCP_UI_PORT:-7008}"
|
|
[pcp-stations-service]="${PCP_STATIONS_PORT:-7009}"
|
|
[pcp-mission-planing-service]="${PCP_MISSION_PORT:-7010}"
|
|
[pcp-tgu-service]="${PCP_TGU_PORT:-7011}"
|
|
[pcp-coverage-scheme-service]="${PCP_COVERAGE_SCHEME_PORT:-7012}"
|
|
[pcp-satellite-catalog-service]="${PCP_SATELLITE_CATALOG_PORT:-7013}"
|
|
[pcp-dynamic-plan-service]="${PCP_DYNAMIC_PLAN_PORT:-7014}"
|
|
)
|
|
|
|
gradle_max_workers="${GRADLE_MAX_WORKERS:-1}"
|
|
gradle_jvmargs="${GRADLE_JVMARGS:--Xmx2g -Dfile.encoding=UTF-8}"
|
|
kotlin_daemon_jvmargs="${KOTLIN_DAEMON_JVMARGS:--Xmx3g -XX:MaxMetaspaceSize=768m}"
|
|
config_server_port="${service_ports[$config_service]}"
|
|
config_server_uri="${LOCAL_CONFIG_SERVER_URI:-http://localhost:$config_server_port}"
|
|
service_profiles="${LOCAL_SERVICE_PROFILES:-local}"
|
|
config_profiles="${LOCAL_CONFIG_PROFILES:-$service_profiles}"
|
|
postgres_host="${PCP_POSTGRES_HOST:-localhost}"
|
|
postgres_port="${PCP_POSTGRES_PORT:-5432}"
|
|
kafka_host="${PCP_KAFKA_HOST:-localhost}"
|
|
kafka_port="${PCP_KAFKA_PORT:-29092}"
|
|
|
|
gradle_common_args=(
|
|
"--no-parallel"
|
|
"--max-workers=$gradle_max_workers"
|
|
"-Dorg.gradle.jvmargs=$gradle_jvmargs"
|
|
"-Pkotlin.daemon.jvmargs=$kotlin_daemon_jvmargs"
|
|
)
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Usage:
|
|
./deploy/local-jar/run-services.sh [command]
|
|
|
|
Commands:
|
|
start Build bootJar artifacts and start local infra, config-server and services.
|
|
restart Stop local jar processes, then run start.
|
|
stop Stop jar processes started by this script.
|
|
status Show pid and log status for local jar processes.
|
|
build Build bootJar artifacts only.
|
|
infra-up Start local Postgres/Kafka via deploy/local-bundle/docker-compose.yml.
|
|
infra-down Stop local Postgres/Kafka containers.
|
|
logs NAME Tail log for a service.
|
|
|
|
Useful environment:
|
|
START_INFRA=false Do not start Postgres/Kafka containers during start.
|
|
INIT_DB=false Do not create local Postgres databases during start.
|
|
WAIT_FOR_APPS=false Do not wait for each app /actuator/health.
|
|
CONFIG_REPO_DIR=... Config repository used by spring-cloud-config-server.
|
|
JAVA_OPTS="-Xmx1g" Extra JVM options for every jar process.
|
|
LOCAL_SERVICE_PROFILES=local,foo
|
|
EOF
|
|
}
|
|
|
|
require_command() {
|
|
local command_name="$1"
|
|
if ! command -v "$command_name" >/dev/null 2>&1; then
|
|
echo "$command_name is required." >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
compose() {
|
|
if docker compose version >/dev/null 2>&1; then
|
|
docker compose --project-directory "$local_bundle_dir" -f "$compose_file" "$@"
|
|
elif command -v docker-compose >/dev/null 2>&1; then
|
|
docker-compose --project-directory "$local_bundle_dir" -f "$compose_file" "$@"
|
|
else
|
|
echo "docker compose or docker-compose is required." >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
http_get() {
|
|
local url="$1"
|
|
if command -v curl >/dev/null 2>&1; then
|
|
curl -fsS "$url" >/dev/null
|
|
elif command -v wget >/dev/null 2>&1; then
|
|
wget -q -O /dev/null "$url"
|
|
else
|
|
return 2
|
|
fi
|
|
}
|
|
|
|
wait_for_http() {
|
|
local name="$1"
|
|
local url="$2"
|
|
local attempts="${3:-90}"
|
|
local attempt
|
|
|
|
for ((attempt = 1; attempt <= attempts; attempt++)); do
|
|
if http_get "$url"; then
|
|
echo "$name is ready: $url"
|
|
return 0
|
|
fi
|
|
sleep 2
|
|
done
|
|
|
|
echo "$name is not ready after $((attempts * 2)) seconds: $url" >&2
|
|
exit 1
|
|
}
|
|
|
|
wait_for_postgres() {
|
|
local attempt
|
|
local postgres_user="${POSTGRES_USER:-postgres}"
|
|
|
|
for attempt in {1..60}; do
|
|
if compose exec -T postgres pg_isready -U "$postgres_user" -d postgres >/dev/null 2>&1; then
|
|
echo "Postgres is ready."
|
|
return 0
|
|
fi
|
|
sleep 2
|
|
done
|
|
|
|
echo "Postgres is not ready after 120 seconds." >&2
|
|
exit 1
|
|
}
|
|
|
|
wait_for_kafka() {
|
|
local attempt
|
|
for attempt in {1..60}; do
|
|
if compose exec -T kafka kafka-topics.sh --bootstrap-server kafka:9092 --list >/dev/null 2>&1; then
|
|
echo "Kafka is ready."
|
|
return 0
|
|
fi
|
|
sleep 2
|
|
done
|
|
|
|
echo "Kafka is not ready after 120 seconds." >&2
|
|
exit 1
|
|
}
|
|
|
|
create_database_if_missing() {
|
|
local db_name="$1"
|
|
local postgres_user="${POSTGRES_USER:-postgres}"
|
|
local exists
|
|
|
|
exists="$(
|
|
compose exec -T postgres psql -U "$postgres_user" -d postgres -tAc \
|
|
"SELECT 1 FROM pg_database WHERE datname = '$db_name'" | tr -d '[:space:]'
|
|
)"
|
|
|
|
if [[ "$exists" == "1" ]]; then
|
|
echo "Database already exists: $db_name"
|
|
return 0
|
|
fi
|
|
|
|
echo "Creating database: $db_name"
|
|
compose exec -T postgres createdb -U "$postgres_user" "$db_name"
|
|
}
|
|
|
|
start_infra() {
|
|
require_command docker
|
|
echo "Starting local Postgres and Kafka..."
|
|
compose up -d postgres kafka
|
|
wait_for_postgres
|
|
wait_for_kafka
|
|
}
|
|
|
|
init_databases() {
|
|
echo "Initializing local service databases..."
|
|
for db_name in "${databases[@]}"; do
|
|
create_database_if_missing "$db_name"
|
|
done
|
|
}
|
|
|
|
build_services() {
|
|
echo "Building bootJar artifacts..."
|
|
echo "Gradle max workers: $gradle_max_workers"
|
|
echo "Gradle JVM args: $gradle_jvmargs"
|
|
echo "Kotlin daemon JVM args: $kotlin_daemon_jvmargs"
|
|
|
|
for service_name in "${all_services[@]}"; do
|
|
echo "Building bootJar for $service_name..."
|
|
"$repo_root/gradlew" "${gradle_common_args[@]}" ":services:$service_name:bootJar"
|
|
done
|
|
}
|
|
|
|
service_pid_file() {
|
|
local service_name="$1"
|
|
printf '%s/%s.pid' "$pid_dir" "$service_name"
|
|
}
|
|
|
|
service_log_file() {
|
|
local service_name="$1"
|
|
printf '%s/%s.log' "$log_dir" "$service_name"
|
|
}
|
|
|
|
is_pid_running() {
|
|
local pid="$1"
|
|
[[ -n "$pid" ]] && kill -0 "$pid" >/dev/null 2>&1
|
|
}
|
|
|
|
read_service_pid() {
|
|
local service_name="$1"
|
|
local pid_file
|
|
|
|
pid_file="$(service_pid_file "$service_name")"
|
|
if [[ -f "$pid_file" ]]; then
|
|
tr -d '[:space:]' < "$pid_file"
|
|
fi
|
|
}
|
|
|
|
find_boot_jar() {
|
|
local service_name="$1"
|
|
local jar_dir="$repo_root/services/$service_name/build/libs"
|
|
local jar_count
|
|
local jar_file
|
|
|
|
if [[ ! -d "$jar_dir" ]]; then
|
|
echo "Missing build/libs for $service_name. Run build first." >&2
|
|
exit 1
|
|
fi
|
|
|
|
jar_count="$(find "$jar_dir" -maxdepth 1 -type f -name '*.jar' ! -name '*-plain.jar' | wc -l)"
|
|
if [[ "$jar_count" != "1" ]]; then
|
|
echo "Expected exactly one bootJar for $service_name, found $jar_count:" >&2
|
|
find "$jar_dir" -maxdepth 1 -type f -name '*.jar' -print >&2 || true
|
|
exit 1
|
|
fi
|
|
|
|
jar_file="$(find "$jar_dir" -maxdepth 1 -type f -name '*.jar' ! -name '*-plain.jar' | head -n 1)"
|
|
printf '%s' "$jar_file"
|
|
}
|
|
|
|
start_service() {
|
|
local service_name="$1"
|
|
local jar_file
|
|
local pid_file
|
|
local log_file
|
|
local existing_pid
|
|
local port="${service_ports[$service_name]}"
|
|
local java_cmd=(java)
|
|
local parsed_java_opts=()
|
|
|
|
pid_file="$(service_pid_file "$service_name")"
|
|
log_file="$(service_log_file "$service_name")"
|
|
existing_pid="$(read_service_pid "$service_name" || true)"
|
|
|
|
if is_pid_running "$existing_pid"; then
|
|
echo "$service_name is already running with pid $existing_pid"
|
|
return 0
|
|
fi
|
|
|
|
mkdir -p "$pid_dir" "$log_dir"
|
|
jar_file="$(find_boot_jar "$service_name")"
|
|
if [[ -n "${JAVA_OPTS:-}" ]]; then
|
|
read -r -a parsed_java_opts <<< "$JAVA_OPTS"
|
|
java_cmd+=("${parsed_java_opts[@]}")
|
|
fi
|
|
java_cmd+=(-jar "$jar_file")
|
|
|
|
echo "Starting $service_name on port $port..."
|
|
if [[ "$service_name" == "$config_service" ]]; then
|
|
(
|
|
cd "$repo_root"
|
|
env \
|
|
SPRING_PROFILES_ACTIVE=local \
|
|
CONFIG_NATIVE_SEARCH_LOCATIONS="file:$config_repo_dir" \
|
|
SERVER_PORT="$config_server_port" \
|
|
"${java_cmd[@]}" > "$log_file" 2>&1 &
|
|
echo "$!" > "$pid_file"
|
|
)
|
|
else
|
|
(
|
|
cd "$repo_root"
|
|
env \
|
|
CONFIG_SERVER_URI="$config_server_uri" \
|
|
CONFIG_SERVER_FAIL_FAST=true \
|
|
SPRING_PROFILES_ACTIVE="$service_profiles" \
|
|
SPRING_CLOUD_CONFIG_PROFILE="$config_profiles" \
|
|
SPRING_CLOUD_CONFIG_LABEL= \
|
|
SPRING_KAFKA_ADMIN_AUTO_CREATE=true \
|
|
SPRING_KAFKA_LISTENER_MISSING_TOPICS_FATAL=false \
|
|
CAMUNDA_CLIENT_ENABLED=false \
|
|
PLANNING_EXTERNAL_UPDATE_ENABLED=false \
|
|
TLE_POLLING_ENABLED=false \
|
|
PCP_POSTGRES_HOST="$postgres_host" \
|
|
PCP_POSTGRES_PORT="$postgres_port" \
|
|
PCP_KAFKA_HOST="$kafka_host" \
|
|
PCP_KAFKA_PORT="$kafka_port" \
|
|
PCP_PORTS_CONFIG="$config_server_port" \
|
|
PCP_PORTS_ADMIN="${service_ports[pcp-srpring-boot-admin-server]}" \
|
|
PCP_PORTS_TLE_MONITORING="${service_ports[tle-monitoring-service]}" \
|
|
PCP_PORTS_COMPLEX_MISSION_SERVICE="${service_ports[pcp-complex-mission-service]}" \
|
|
PCP_PORTS_BALLISTICS="${service_ports[pcp-ballistics-service]}" \
|
|
PCP_PORTS_ROUTE_PROCESSING="${service_ports[pcp-route-processing-service]}" \
|
|
PCP_PORTS_REQUEST="${service_ports[pcp-request-service]}" \
|
|
PCP_PORTS_SLOTS="${service_ports[slots-service]}" \
|
|
PCP_PORTS_UI="${service_ports[pcp-ui-service]}" \
|
|
PCP_PORTS_STATIONS="${service_ports[pcp-stations-service]}" \
|
|
PCP_PORTS_MISSION="${service_ports[pcp-mission-planing-service]}" \
|
|
PCP_PORTS_TGU="${service_ports[pcp-tgu-service]}" \
|
|
PCP_PORTS_COVERAGE_SCHEME="${service_ports[pcp-coverage-scheme-service]}" \
|
|
PCP_PORTS_SATELLITE_CATALOG="${service_ports[pcp-satellite-catalog-service]}" \
|
|
PCP_PORTS_DYNAMIC_PLAN="${service_ports[pcp-dynamic-plan-service]}" \
|
|
"${java_cmd[@]}" > "$log_file" 2>&1 &
|
|
echo "$!" > "$pid_file"
|
|
)
|
|
fi
|
|
|
|
echo "$service_name log: $log_file"
|
|
}
|
|
|
|
start_config_server() {
|
|
if [[ ! -d "$config_repo_dir" ]]; then
|
|
echo "Config repo directory does not exist: $config_repo_dir" >&2
|
|
exit 1
|
|
fi
|
|
|
|
start_service "$config_service"
|
|
wait_for_http "$config_service" "$config_server_uri/actuator/health"
|
|
wait_for_http "$config_service config-repo lookup" "$config_server_uri/pcp-request-service/local"
|
|
}
|
|
|
|
wait_for_service_health() {
|
|
local service_name="$1"
|
|
local port="${service_ports[$service_name]}"
|
|
wait_for_http "$service_name" "http://localhost:$port/actuator/health" "${APP_HEALTH_ATTEMPTS:-90}"
|
|
}
|
|
|
|
start_app_services() {
|
|
for service_name in "${app_services[@]}"; do
|
|
start_service "$service_name"
|
|
if [[ "${WAIT_FOR_APPS:-true}" == "true" ]]; then
|
|
wait_for_service_health "$service_name"
|
|
fi
|
|
done
|
|
}
|
|
|
|
stop_service() {
|
|
local service_name="$1"
|
|
local pid_file
|
|
local pid
|
|
local attempt
|
|
|
|
pid_file="$(service_pid_file "$service_name")"
|
|
pid="$(read_service_pid "$service_name" || true)"
|
|
if ! is_pid_running "$pid"; then
|
|
rm -f "$pid_file"
|
|
echo "$service_name is not running."
|
|
return 0
|
|
fi
|
|
|
|
echo "Stopping $service_name with pid $pid..."
|
|
kill "$pid" >/dev/null 2>&1 || true
|
|
for attempt in {1..30}; do
|
|
if ! is_pid_running "$pid"; then
|
|
rm -f "$pid_file"
|
|
return 0
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
echo "Force stopping $service_name with pid $pid..."
|
|
kill -9 "$pid" >/dev/null 2>&1 || true
|
|
rm -f "$pid_file"
|
|
}
|
|
|
|
stop_services() {
|
|
local service_name
|
|
local idx
|
|
|
|
for ((idx = ${#app_services[@]} - 1; idx >= 0; idx--)); do
|
|
service_name="${app_services[$idx]}"
|
|
stop_service "$service_name"
|
|
done
|
|
stop_service "$config_service"
|
|
}
|
|
|
|
status_services() {
|
|
local service_name
|
|
local pid
|
|
local log_file
|
|
|
|
printf '%-36s %-10s %s\n' "service" "pid" "log"
|
|
for service_name in "${all_services[@]}"; do
|
|
pid="$(read_service_pid "$service_name" || true)"
|
|
log_file="$(service_log_file "$service_name")"
|
|
if is_pid_running "$pid"; then
|
|
printf '%-36s %-10s %s\n' "$service_name" "$pid" "$log_file"
|
|
else
|
|
printf '%-36s %-10s %s\n' "$service_name" "-" "$log_file"
|
|
fi
|
|
done
|
|
}
|
|
|
|
tail_logs() {
|
|
local service_name="${1:-}"
|
|
local log_file
|
|
|
|
if [[ -z "$service_name" ]]; then
|
|
echo "Service name is required for logs command." >&2
|
|
exit 1
|
|
fi
|
|
|
|
log_file="$(service_log_file "$service_name")"
|
|
if [[ ! -f "$log_file" ]]; then
|
|
echo "Log file does not exist: $log_file" >&2
|
|
exit 1
|
|
fi
|
|
|
|
tail -f "$log_file"
|
|
}
|
|
|
|
start_all() {
|
|
require_command java
|
|
|
|
build_services
|
|
|
|
if [[ "${START_INFRA:-true}" == "true" ]]; then
|
|
start_infra
|
|
if [[ "${INIT_DB:-true}" == "true" ]]; then
|
|
init_databases
|
|
fi
|
|
else
|
|
echo "Skipping local infra startup. Expecting Postgres at $postgres_host:$postgres_port and Kafka at $kafka_host:$kafka_port."
|
|
fi
|
|
|
|
start_config_server
|
|
start_app_services
|
|
|
|
echo "Local jar startup requested."
|
|
status_services
|
|
}
|
|
|
|
command="${1:-start}"
|
|
case "$command" in
|
|
start)
|
|
start_all
|
|
;;
|
|
restart)
|
|
stop_services
|
|
start_all
|
|
;;
|
|
stop)
|
|
stop_services
|
|
;;
|
|
status)
|
|
status_services
|
|
;;
|
|
build)
|
|
build_services
|
|
;;
|
|
infra-up)
|
|
start_infra
|
|
if [[ "${INIT_DB:-true}" == "true" ]]; then
|
|
init_databases
|
|
fi
|
|
;;
|
|
infra-down)
|
|
require_command docker
|
|
compose stop kafka postgres
|
|
;;
|
|
logs)
|
|
tail_logs "${2:-}"
|
|
;;
|
|
help|-h|--help)
|
|
usage
|
|
;;
|
|
*)
|
|
usage >&2
|
|
exit 1
|
|
;;
|
|
esac
|