Add pm2 helper scripts and README

This commit is contained in:
2026-06-08 21:36:11 +00:00
parent 8e37925205
commit ce97bfa3ea
3 changed files with 272 additions and 0 deletions
+209
View File
@@ -0,0 +1,209 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
declare -a APP_NAMES=()
declare -a APP_DIRS=()
declare -a APP_ECOSYSTEMS=()
trim() {
local s="$1"
s="${s#"${s%%[![:space:]]*}"}"
s="${s%"${s##*[![:space:]]}"}"
printf "%s" "$s"
}
extract_app_name() {
local ecosystem_file="$1"
local name
name="$(grep -E 'name:[[:space:]]*"[^"]+"' "$ecosystem_file" | head -n1 | sed -E 's/.*name:[[:space:]]*"([^"]+)".*/\1/' || true)"
name="$(trim "$name")"
if [ -z "$name" ]; then
name="$(basename "$(dirname "$ecosystem_file")")"
fi
printf "%s" "$name"
}
discover_ecosystems() {
local file app_name project_dir
while IFS= read -r file; do
project_dir="$(dirname "$file")"
app_name="$(extract_app_name "$file")"
APP_NAMES+=("$app_name")
APP_DIRS+=("$project_dir")
APP_ECOSYSTEMS+=("$file")
done < <(
find "$ROOT_DIR" -mindepth 2 -maxdepth 2 -type f \
\( -name "ecosystem.config.cjs" -o -name "ecosystem.cron.config.js" \) \
| sort
)
}
print_services() {
local i rel
if [ "${#APP_NAMES[@]}" -eq 0 ]; then
echo "No ecosystem config files found under $ROOT_DIR"
return
fi
echo "Discovered services:"
for i in "${!APP_NAMES[@]}"; do
rel="${APP_ECOSYSTEMS[$i]#"$ROOT_DIR/"}"
printf " %2d) %-18s %s\n" "$((i + 1))" "${APP_NAMES[$i]}" "$rel"
done
}
run_action() {
local action="$1"
local app_name="$2"
local project_dir="$3"
local ecosystem_file="$4"
cd "$project_dir"
case "$action" in
recreate)
echo "Recreating '$app_name' from '$ecosystem_file'..."
pm2 delete "$app_name" >/dev/null 2>&1 || true
pm2 start "$ecosystem_file"
pm2 save
;;
reload)
echo "Reloading '$app_name'..."
pm2 reload "$app_name" --update-env
pm2 save
;;
restart)
echo "Restarting '$app_name'..."
pm2 restart "$app_name" --update-env
pm2 save
;;
delete)
echo "Deleting '$app_name'..."
pm2 delete "$app_name"
pm2 save
;;
*)
echo "Unknown action: $action"
exit 1
;;
esac
}
interactive_mode() {
local action_pick action idx
print_services
echo
echo "Choose action:"
echo " 1) Recreate from ecosystem (best for .env/config changes)"
echo " 2) Reload"
echo " 3) Restart"
echo " 4) Delete"
read -r -p "Action [1]: " action_pick
action_pick="${action_pick:-1}"
case "$action_pick" in
1) action="recreate" ;;
2) action="reload" ;;
3) action="restart" ;;
4) action="delete" ;;
*) echo "Invalid action"; exit 1 ;;
esac
echo
read -r -p "Service number: " idx
if ! [[ "$idx" =~ ^[0-9]+$ ]]; then
echo "Invalid service number"
exit 1
fi
idx=$((idx - 1))
if [ "$idx" -lt 0 ] || [ "$idx" -ge "${#APP_NAMES[@]}" ]; then
echo "Service number out of range"
exit 1
fi
echo
run_action "$action" "${APP_NAMES[$idx]}" "${APP_DIRS[$idx]}" "${APP_ECOSYSTEMS[$idx]}"
echo
pm2 ls
}
usage() {
cat <<EOF
Usage:
$0 # interactive mode
$0 list
$0 <action> <service>
Actions:
recreate | reload | restart | delete
Service can be:
- numeric index from "list"
- app name (e.g. zap, zap-cleanup, caddy-manager, api)
EOF
}
resolve_service_index() {
local target="$1"
local i
if [[ "$target" =~ ^[0-9]+$ ]]; then
i=$((target - 1))
if [ "$i" -ge 0 ] && [ "$i" -lt "${#APP_NAMES[@]}" ]; then
echo "$i"
return 0
fi
return 1
fi
for i in "${!APP_NAMES[@]}"; do
if [ "${APP_NAMES[$i]}" = "$target" ]; then
echo "$i"
return 0
fi
done
return 1
}
main() {
if [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ]; then
usage
exit 0
fi
discover_ecosystems
if [ "${1:-}" = "list" ]; then
print_services
exit 0
fi
if [ $# -eq 0 ]; then
interactive_mode
exit 0
fi
if [ $# -ne 2 ]; then
usage
exit 1
fi
local action="$1"
local target="$2"
local idx
if ! idx="$(resolve_service_index "$target")"; then
echo "Unknown service: $target"
echo
print_services
exit 1
fi
run_action "$action" "${APP_NAMES[$idx]}" "${APP_DIRS[$idx]}" "${APP_ECOSYSTEMS[$idx]}"
}
main "$@"