Files
cannaiq/scripts/stale-process-monitor.sh
Kelly d91c55a344 feat: Add stale process monitor, users route, landing page, archive old scripts
- Add backend stale process monitoring API (/api/stale-processes)
- Add users management route
- Add frontend landing page and stale process monitor UI on /scraper-tools
- Move old development scripts to backend/archive/
- Update frontend build with new features

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 04:07:31 -07:00

249 lines
6.4 KiB
Bash
Executable File

#!/bin/bash
# Stale Process Monitor
# Manages and cleans up stale background processes from Claude Code sessions
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Process patterns to monitor
STALE_PATTERNS=(
"kubectl port-forward"
"npm run dev"
"npx tsx"
"node dist/index.js"
"docker push"
"kubectl exec"
)
# Maximum age in minutes before a process is considered stale
MAX_AGE_MINUTES=${MAX_AGE_MINUTES:-60}
print_header() {
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE} Stale Process Monitor${NC}"
echo -e "${BLUE}========================================${NC}"
echo ""
}
list_processes() {
local pattern="$1"
local count=0
while IFS= read -r line; do
if [[ -n "$line" ]]; then
((count++))
local pid=$(echo "$line" | awk '{print $1}')
local start_time=$(ps -o lstart= -p "$pid" 2>/dev/null || echo "unknown")
local elapsed=$(ps -o etime= -p "$pid" 2>/dev/null | tr -d ' ' || echo "unknown")
local cmd=$(echo "$line" | awk '{$1=""; $2=""; print $0}' | sed 's/^ *//')
echo -e " ${YELLOW}PID:${NC} $pid ${YELLOW}Elapsed:${NC} $elapsed"
echo -e " ${YELLOW}Cmd:${NC} ${cmd:0:80}..."
echo ""
fi
done < <(ps aux | grep -E "$pattern" | grep -v grep | grep -v "stale-process-monitor")
return $count
}
show_status() {
print_header
echo -e "${GREEN}Scanning for potentially stale processes...${NC}"
echo ""
local total=0
for pattern in "${STALE_PATTERNS[@]}"; do
local matches=$(ps aux | grep -E "$pattern" | grep -v grep | grep -v "stale-process-monitor" | wc -l)
if [[ $matches -gt 0 ]]; then
echo -e "${YELLOW}[$pattern]${NC} - $matches process(es) found:"
echo ""
list_processes "$pattern"
((total += matches))
fi
done
echo -e "${BLUE}----------------------------------------${NC}"
echo -e "${GREEN}Total potentially stale processes: $total${NC}"
echo ""
if [[ $total -eq 0 ]]; then
echo -e "${GREEN}No stale processes detected.${NC}"
fi
}
kill_pattern() {
local pattern="$1"
local dry_run="$2"
# Get PIDs from the second column (proper PID column in ps aux)
local pids=$(ps aux | grep -E "$pattern" | grep -v grep | grep -v "stale-process-monitor" | awk '{print $2}')
if [[ -z "$pids" ]]; then
echo -e "${YELLOW}No processes matching '$pattern'${NC}"
return 0
fi
for pid in $pids; do
# Validate that it's actually a number
if [[ "$pid" =~ ^[0-9]+$ ]]; then
if [[ "$dry_run" == "true" ]]; then
echo -e "${YELLOW}[DRY-RUN] Would kill PID $pid${NC}"
else
echo -e "${RED}Killing PID $pid...${NC}"
kill -9 "$pid" 2>/dev/null || echo -e "${YELLOW} (already dead)${NC}"
fi
fi
done
}
clean_all() {
local dry_run="$1"
print_header
if [[ "$dry_run" == "true" ]]; then
echo -e "${YELLOW}DRY RUN MODE - No processes will be killed${NC}"
else
echo -e "${RED}CLEANING ALL STALE PROCESSES${NC}"
fi
echo ""
for pattern in "${STALE_PATTERNS[@]}"; do
echo -e "${BLUE}Processing: $pattern${NC}"
kill_pattern "$pattern" "$dry_run"
echo ""
done
echo -e "${GREEN}Cleanup complete.${NC}"
}
clean_port_forwards() {
local dry_run="$1"
print_header
echo -e "${BLUE}Cleaning kubectl port-forward processes...${NC}"
echo ""
kill_pattern "kubectl port-forward" "$dry_run"
echo ""
echo -e "${GREEN}Port-forward cleanup complete.${NC}"
}
clean_dev_servers() {
local dry_run="$1"
print_header
echo -e "${BLUE}Cleaning npm run dev processes...${NC}"
echo ""
kill_pattern "npm run dev" "$dry_run"
kill_pattern "vite" "$dry_run"
kill_pattern "node.*dist/index.js" "$dry_run"
echo ""
echo -e "${GREEN}Dev server cleanup complete.${NC}"
}
interactive_menu() {
while true; do
print_header
echo "Options:"
echo " 1) Show status (list all stale processes)"
echo " 2) Clean all stale processes"
echo " 3) Clean all (dry-run)"
echo " 4) Clean port-forwards only"
echo " 5) Clean dev servers only"
echo " 6) Clean specific pattern"
echo " q) Quit"
echo ""
read -p "Select option: " choice
case $choice in
1) show_status ;;
2) clean_all "false" ;;
3) clean_all "true" ;;
4) clean_port_forwards "false" ;;
5) clean_dev_servers "false" ;;
6)
read -p "Enter pattern to clean: " pattern
kill_pattern "$pattern" "false"
;;
q|Q) exit 0 ;;
*) echo -e "${RED}Invalid option${NC}" ;;
esac
echo ""
read -p "Press Enter to continue..."
done
}
usage() {
echo "Usage: $0 [command]"
echo ""
echo "Commands:"
echo " status Show all potentially stale processes"
echo " clean Clean all stale processes"
echo " clean-dry Dry-run cleanup (show what would be killed)"
echo " ports Clean kubectl port-forward processes only"
echo " devs Clean dev server processes only"
echo " kill <pat> Kill processes matching pattern"
echo " interactive Interactive menu mode"
echo ""
echo "Environment variables:"
echo " MAX_AGE_MINUTES Maximum process age before considered stale (default: 60)"
echo ""
echo "Examples:"
echo " $0 status"
echo " $0 clean"
echo " $0 kill 'kubectl port-forward'"
}
# Main
case "${1:-}" in
status)
show_status
;;
clean)
clean_all "false"
;;
clean-dry)
clean_all "true"
;;
ports)
clean_port_forwards "false"
;;
devs)
clean_dev_servers "false"
;;
kill)
if [[ -z "${2:-}" ]]; then
echo "Error: Pattern required"
usage
exit 1
fi
kill_pattern "$2" "false"
;;
interactive|i)
interactive_menu
;;
help|-h|--help)
usage
;;
"")
show_status
;;
*)
echo "Unknown command: $1"
usage
exit 1
;;
esac