From 66a08b61d2141f294c56a33511fa78673d04a73a Mon Sep 17 00:00:00 2001 From: Deploy Date: Tue, 25 Aug 2026 21:59:29 +0200 Subject: [PATCH] fix: clean stale deployments before monolith start --- .../admin/src/app/(dashboard)/pos/page.tsx | 3 + .../migrations/061_payment_partial_refund.js | 17 ++++ project/migrations/063_pos_store_logo_url.js | 4 +- project/scripts/monolith.sh | 87 ++++++++++++++----- 4 files changed, 89 insertions(+), 22 deletions(-) create mode 100644 project/migrations/061_payment_partial_refund.js diff --git a/project/apps/admin/src/app/(dashboard)/pos/page.tsx b/project/apps/admin/src/app/(dashboard)/pos/page.tsx index 7f03321..2d934a8 100644 --- a/project/apps/admin/src/app/(dashboard)/pos/page.tsx +++ b/project/apps/admin/src/app/(dashboard)/pos/page.tsx @@ -890,6 +890,7 @@ function Field({ required = false, min, max, + placeholder, }: { label: string; value: string; @@ -898,6 +899,7 @@ function Field({ required?: boolean; min?: number; max?: number; + placeholder?: string; }) { return ( diff --git a/project/migrations/061_payment_partial_refund.js b/project/migrations/061_payment_partial_refund.js new file mode 100644 index 0000000..8066e37 --- /dev/null +++ b/project/migrations/061_payment_partial_refund.js @@ -0,0 +1,17 @@ +/** + * Compatibility marker for the historical payment partial-refund migration. + * + * Some long-lived local databases have this migration recorded in pgmigrations, + * but the repository no longer carried the file. node-pg-migrate rejects later + * migrations when an already-run migration is missing from disk, so keep this + * no-op marker to preserve ordering between 060 and 062. + * + * Current partial-refund schema support is already covered by previous + * reporting/POS migrations (notably 053 and 056). + */ + +/** @param {import('pg-migrate').MigrationBuilder} _pgm */ +export const up = (_pgm) => {}; + +/** @param {import('pg-migrate').MigrationBuilder} _pgm */ +export const down = (_pgm) => {}; diff --git a/project/migrations/063_pos_store_logo_url.js b/project/migrations/063_pos_store_logo_url.js index 97fa952..fb699c4 100644 --- a/project/migrations/063_pos_store_logo_url.js +++ b/project/migrations/063_pos_store_logo_url.js @@ -10,7 +10,9 @@ exports.up = (pgm) => { default: null, }, }); - pgm.addCommentOnColumn('pos_stores', 'logo_url', 'URL del logo custom para tickets TPV. Si es null, se usa el logo default /images/logo-main.png'); + pgm.sql( + "COMMENT ON COLUMN pos_stores.logo_url IS 'URL del logo custom para tickets TPV. Si es null, se usa el logo default /images/logo-main.png'", + ); }; exports.down = (pgm) => { diff --git a/project/scripts/monolith.sh b/project/scripts/monolith.sh index fe521eb..a093c0f 100755 --- a/project/scripts/monolith.sh +++ b/project/scripts/monolith.sh @@ -130,6 +130,69 @@ port_pid() { fi } +port_pids() { + local port="$1" + if command -v lsof >/dev/null 2>&1; then + lsof -nP -tiTCP:"$port" -sTCP:LISTEN 2>/dev/null | sort -u || true + fi +} + +stop_pid() { + local pid="$1" label="$2" deadline + [[ -n "$pid" ]] || return 0 + if ! kill -0 "$pid" 2>/dev/null; then + return 0 + fi + echo "[INFO] Stopping $label (PID $pid)..." + kill -TERM "$pid" 2>/dev/null || true + deadline=$((SECONDS + 15)) + while kill -0 "$pid" 2>/dev/null && (( SECONDS < deadline )); do sleep 1; done + if kill -0 "$pid" 2>/dev/null; then + echo "[WARN] $label did not stop gracefully; sending KILL" + kill -KILL "$pid" 2>/dev/null || true + fi +} + +stop_service_port_listeners() { + local service="$1" port pid found=0 + port="$(service_port "$service")" + while IFS= read -r pid; do + [[ -n "$pid" ]] || continue + found=1 + stop_pid "$pid" "stale $service listener on port $port" + done < <(port_pids "$port") + if [[ "$found" == 1 ]]; then + rm -f "$(pid_file "$service")" + fi +} + +stop_stale_project_processes() { + local pid cmd + while IFS= read -r line; do + pid="${line%% *}" + cmd="${line#* }" + [[ -n "$pid" && "$pid" =~ ^[0-9]+$ ]] || continue + [[ "$pid" == "$$" || "$pid" == "$BASHPID" ]] && continue + case "$cmd" in + *"$PROJECT_DIR"*"tsx"*"watch src/infrastructure/http/server.ts"*|\ + *"$PROJECT_DIR"*"node_modules/tsx/dist/cli.mjs watch src/infrastructure/http/server.ts"*|\ + *"$PROJECT_DIR"*"next start"*|\ + *"$PROJECT_DIR"*"node_modules/next/dist/bin/next start"*) + stop_pid "$pid" "stale project process" + ;; + esac + done < <(ps -axo pid=,command= 2>/dev/null | sed 's/^ *//') +} + +clear_stale_deployments() { + echo '[INFO] Clearing old service deployments from managed ports...' + stop_stale_project_processes + local service + for service in "${SERVICES[@]}"; do + stop_service_port_listeners "$service" + done +} + assert_port_available() { local service="$1" port existing managed port="$(service_port "$service")" @@ -301,11 +364,8 @@ spawn_service() { start_all() { ensure_env + clear_stale_deployments for service in "${SERVICES[@]}"; do - if is_running "$service"; then - echo "[FAIL] $service is already managed in $MODE mode; use restart" >&2 - exit 1 - fi rm -f "$(pid_file "$service")" assert_port_available "$service" done @@ -320,24 +380,9 @@ start_all() { } stop_service() { - local service="$1" pid deadline + local service="$1" pid pid="$(read_pid "$service")" - if [[ -z "$pid" ]]; then - rm -f "$(pid_file "$service")" - return - fi - if ! kill -0 "$pid" 2>/dev/null; then - rm -f "$(pid_file "$service")" - return - fi - echo "[INFO] Stopping $service (PID $pid)..." - kill -TERM "$pid" 2>/dev/null || true - deadline=$((SECONDS + 15)) - while kill -0 "$pid" 2>/dev/null && (( SECONDS < deadline )); do sleep 1; done - if kill -0 "$pid" 2>/dev/null; then - echo "[WARN] $service did not stop gracefully; sending KILL" - kill -KILL "$pid" 2>/dev/null || true - fi + stop_pid "$pid" "$service" rm -f "$(pid_file "$service")" }