chore: сохранение текущих изменений (deploy local-bundle/local-jar, request-service, slots UI markedObjectIds)

Безопасный коммит незакоммиченной работы перед реализацией бронирования слотов.
Вне коммита оставлены: package-lock.json (пустой, мусор), requests.json (scratch-данные).
This commit is contained in:
Дмитрий Соловьев
2026-06-11 14:00:12 +03:00
parent 6689351ef0
commit 345529cde0
36 changed files with 1674 additions and 37 deletions
+538
View File
@@ -0,0 +1,538 @@
#!/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