| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481 |
- #!/bin/bash
- # ===========================================
- # 学生状态变更处理脚本控制程序 - 生产环境版本
- # 用于启动、停止、重启处理脚本 (Ubuntu兼容性修复版本)
- # ===========================================
- #
- # 生产环境部署指南:
- # 1. 确保所有修复版本脚本存在:
- # - process_student_changes_fixed.sh (状态变更处理)
- # - process_student_resume_fixed.sh (复学处理)
- #
- # 2. 确保配置文件存在:
- # - data.conf (数据库配置和脚本参数)
- #
- # 3. 启动所有服务:
- # ./control_scripts.sh startall
- #
- # 4. 监控运行状态:
- # ./control_scripts.sh statusall
- #
- # 5. 健康检查:
- # ./control_scripts.sh health all
- #
- # 6. 查看系统资源:
- # ./control_scripts.sh info
- #
- # 日志文件位置:
- # - 控制脚本日志: logs/control_scripts_YYYYMMDD.log
- # - 处理脚本日志: student_status_change/process_student_*_YYYYMMDD_HHMMSS.log
- # Disable strict error checking for better production resilience
- # set -euo pipefail # Temporarily disabled for production robustness
- # Force C locale for consistent behavior across systems
- export LANG=C
- export LC_ALL=C
- # Load configuration
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
- CONFIG_FILE="${SCRIPT_DIR}/data.conf"
- if [[ ! -f "$CONFIG_FILE" ]]; then
- echo "错误:配置文件 $CONFIG_FILE 未找到!"
- echo "请确保 data.conf 文件存在于脚本目录中"
- exit 1
- fi
- source "$CONFIG_FILE"
- # Production environment setup
- PRODUCTION_LOG_DIR="${SCRIPT_DIR}/logs"
- mkdir -p "$PRODUCTION_LOG_DIR"
- PRODUCTION_LOG_FILE="${PRODUCTION_LOG_DIR}/control_scripts_$(date +%Y%m%d).log"
- # Script definitions - Production versions with Ubuntu compatibility fixes
- # Using indexed arrays for better bash compatibility
- SCRIPT_NAMES=("changes" "resume")
- SCRIPT_FILES=("process_student_changes_fixed.sh" "process_student_resume_fixed.sh")
- # Function to get script file by name
- get_script_file() {
- local script_name="$1"
- for i in "${!SCRIPT_NAMES[@]}"; do
- if [[ "${SCRIPT_NAMES[$i]}" == "$script_name" ]]; then
- echo "${SCRIPT_FILES[$i]}"
- return 0
- fi
- done
- return 1
- }
- # PID files
- PID_DIR="${SCRIPT_DIR}/pids"
- mkdir -p "$PID_DIR"
- # Functions
- log() {
- local level="$1"
- local message="$2"
- local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
- local log_message="[$timestamp] [$level] $message"
- # Output to console
- echo "$log_message"
- # Output to production log file
- echo "$log_message" >> "$PRODUCTION_LOG_FILE"
- }
- get_pid_file() {
- local script_name="$1"
- echo "${PID_DIR}/${script_name}.pid"
- }
- get_lock_file() {
- local script_name="$1"
- echo "${SCRIPT_DIR}/${script_name}.lock"
- }
- is_running() {
- local script_name="$1"
- local pid_file=$(get_pid_file "$script_name")
- local lock_file=$(get_lock_file "$script_name")
- # Check PID file
- if [[ -f "$pid_file" ]]; then
- local pid=$(cat "$pid_file")
- if kill -0 "$pid" 2>/dev/null; then
- return 0 # Running
- else
- log "WARN" "删除脚本 $script_name 的过期PID文件"
- rm -f "$pid_file"
- fi
- fi
- # Check lock file
- if [[ -f "$lock_file" ]]; then
- local lock_pid=$(cat "$lock_file")
- if kill -0 "$lock_pid" 2>/dev/null; then
- return 0 # Running
- else
- log "WARN" "删除脚本 $script_name 的过期锁定文件"
- rm -f "$lock_file"
- fi
- fi
- return 1 # Not running
- }
- # Health check function for production monitoring
- health_check() {
- local script_name="$1"
- local script_file="${SCRIPT_DIR}/$(get_script_file "$script_name")"
- log "INFO" "执行 $script_name 的健康检查..."
- # Check if script file exists and is executable
- if [[ ! -f "$script_file" ]]; then
- log "ERROR" "$script_name 脚本文件不存在: $script_file"
- return 1
- fi
- if [[ ! -x "$script_file" ]]; then
- log "WARN" "$script_name 脚本文件没有执行权限,正在修复..."
- chmod +x "$script_file"
- fi
- # Check database connectivity
- if ! mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "SELECT 1;" >/dev/null 2>&1; then
- log "ERROR" "$script_name 数据库连接失败"
- return 1
- fi
- # Check if script is running
- if ! is_running "$script_name"; then
- log "WARN" "$script_name 脚本未运行"
- return 1
- fi
- log "INFO" "$script_name 健康检查通过"
- return 0
- }
- # Get system resource usage
- get_system_info() {
- log "INFO" "=== 系统资源信息 ==="
- # CPU usage
- local cpu_usage=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}')
- log "INFO" "CPU使用率: ${cpu_usage}%"
- # Memory usage
- local mem_info=$(free -h | grep "^Mem:")
- log "INFO" "内存信息: $mem_info"
- # Disk usage
- local disk_info=$(df -h "$SCRIPT_DIR" | tail -1 | awk '{print $1 ": " $5 " used (" $4 " free)"}')
- log "INFO" "磁盘使用: $disk_info"
- # Process count
- local process_count=$(pgrep -f "process_student.*\.sh" | wc -l)
- log "INFO" "运行中的学生处理进程数: $process_count"
- }
- start_script() {
- local script_name="$1"
- local script_file="${SCRIPT_DIR}/$(get_script_file "$script_name")"
- local pid_file=$(get_pid_file "$script_name")
- if [[ ! -f "$script_file" ]]; then
- log "ERROR" "脚本文件未找到: $script_file"
- return 1
- fi
- if is_running "$script_name"; then
- log "INFO" "$script_name 已在运行"
- return 0
- fi
- log "INFO" "正在启动 $script_name..."
- chmod +x "$script_file"
- # Start script in background
- nohup "$script_file" > /dev/null 2>&1 &
- local pid=$!
- # Wait a moment for script to start
- sleep 2
- if kill -0 "$pid" 2>/dev/null; then
- echo $pid > "$pid_file"
- log "INFO" "$script_name 启动成功 (PID: $pid)"
- return 0
- else
- log "ERROR" "$script_name 启动失败"
- return 1
- fi
- }
- stop_script() {
- local script_name="$1"
- local pid_file=$(get_pid_file "$script_name")
- local lock_file=$(get_lock_file "$script_name")
- local stopped=false
- log "INFO" "正在停止 $script_name..."
- # 尝试通过PID文件停止
- if [[ -f "$pid_file" ]]; then
- local pid=$(cat "$pid_file")
- if kill -0 "$pid" 2>/dev/null; then
- kill "$pid"
- sleep 2
- if ! kill -0 "$pid" 2>/dev/null; then
- log "INFO" "$script_name 停止成功 (PID: $pid)"
- stopped=true
- fi
- fi
- rm -f "$pid_file"
- fi
- # 尝试通过锁定文件停止
- if [[ -f "$lock_file" ]]; then
- local lock_pid=$(cat "$lock_file")
- if kill -0 "$lock_pid" 2>/dev/null; then
- kill "$lock_pid"
- sleep 2
- if ! kill -0 "$lock_pid" 2>/dev/null; then
- log "INFO" "$script_name 停止成功 (PID: $lock_pid)"
- stopped=true
- fi
- fi
- rm -f "$lock_file"
- fi
- if [[ "$stopped" == false ]]; then
- log "WARN" "$script_name 可能未运行或优雅停止失败"
- fi
- }
- restart_script() {
- local script_name="$1"
- log "INFO" "正在重启 $script_name..."
- stop_script "$script_name"
- sleep 3
- start_script "$script_name"
- }
- status_script() {
- local script_name="$1"
- if is_running "$script_name"; then
- local pid_file=$(get_pid_file "$script_name")
- local lock_file=$(get_lock_file "$script_name")
- if [[ -f "$pid_file" ]]; then
- local pid=$(cat "$pid_file")
- log "INFO" "$script_name 正在运行 (PID: $pid)"
- elif [[ -f "$lock_file" ]]; then
- local lock_pid=$(cat "$lock_file")
- log "INFO" "$script_name 正在运行 (PID: $lock_pid)"
- else
- log "INFO" "$script_name 状态未知"
- fi
- else
- log "INFO" "$script_name 未运行"
- fi
- }
- show_usage() {
- cat << EOF
- 用法: $0 <命令> <脚本名称>
- 命令:
- start 启动指定的脚本
- stop 停止指定的脚本
- restart 重启指定的脚本
- status 显示指定脚本的状态
- health 执行脚本健康检查
- startall 启动所有脚本
- stopall 停止所有脚本
- statusall 显示所有脚本的状态
- info 显示系统资源信息
- 脚本名称:
- changes 学生状态变更脚本 (休学/退学/毕业) - Ubuntu兼容修复版本
- resume 学生复学脚本 (复学) - Ubuntu兼容修复版本
- all 所有脚本
- 生产环境示例:
- $0 startall # 启动所有学生处理脚本
- $0 statusall # 检查所有脚本运行状态
- $0 health all # 执行所有脚本的健康检查
- $0 info # 查看系统资源使用情况
- $0 restart changes # 重启状态变更处理脚本
- $0 stopall # 停止所有处理脚本
- 传统示例:
- $0 start changes # 启动状态变更处理脚本
- $0 stop resume # 停止复学处理脚本
- $0 status changes # 显示状态变更脚本状态
- 注意:
- 本脚本使用修复版本,已适配Ubuntu环境,解决了循环处理和数据库查询的兼容性问题
- EOF
- }
- # Production environment initialization
- init_production_env() {
- log "INFO" "初始化生产环境..."
- # Check script files exist
- for script_name in "${!SCRIPTS[@]}"; do
- local script_file="${SCRIPT_DIR}/${SCRIPTS[$script_name]}"
- if [[ ! -f "$script_file" ]]; then
- log "ERROR" "脚本文件不存在: $script_file"
- log "ERROR" "请确保已部署修复版本的脚本文件"
- exit 1
- fi
- done
- # Test database connectivity
- if ! mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "SELECT 1;" >/dev/null 2>&1; then
- log "ERROR" "数据库连接失败,请检查配置"
- exit 1
- fi
- log "INFO" "生产环境初始化完成"
- }
- # Main function
- main() {
- # Initialize production environment
- init_production_env
- local command="${1:-}"
- local script_name="${2:-}"
- case "$command" in
- start)
- if [[ "$script_name" == "all" ]]; then
- for script in "${SCRIPT_NAMES[@]}"; do
- start_script "$script"
- done
- elif get_script_file "$script_name" >/dev/null 2>&1; then
- start_script "$script_name"
- else
- log "ERROR" "未知的脚本名称: $script_name"
- show_usage
- exit 1
- fi
- ;;
- stop)
- if [[ "$script_name" == "all" ]]; then
- for script in "${SCRIPT_NAMES[@]}"; do
- stop_script "$script"
- done
- elif get_script_file "$script_name" >/dev/null 2>&1; then
- stop_script "$script_name"
- else
- log "ERROR" "未知的脚本名称: $script_name"
- show_usage
- exit 1
- fi
- ;;
- restart)
- if [[ "$script_name" == "all" ]]; then
- for script in "${SCRIPT_NAMES[@]}"; do
- restart_script "$script"
- done
- elif get_script_file "$script_name" >/dev/null 2>&1; then
- restart_script "$script_name"
- else
- log "ERROR" "未知的脚本名称: $script_name"
- show_usage
- exit 1
- fi
- ;;
- status)
- if [[ "$script_name" == "all" ]]; then
- for script in "${SCRIPT_NAMES[@]}"; do
- status_script "$script"
- done
- elif get_script_file "$script_name" >/dev/null 2>&1; then
- status_script "$script_name"
- else
- log "ERROR" "未知的脚本名称: $script_name"
- show_usage
- exit 1
- fi
- ;;
- startall)
- log "INFO" "正在启动所有脚本..."
- for script in "${SCRIPT_NAMES[@]}"; do
- start_script "$script"
- done
- ;;
- stopall)
- log "INFO" "正在停止所有脚本..."
- for script in "${SCRIPT_NAMES[@]}"; do
- stop_script "$script"
- done
- ;;
- statusall)
- log "INFO" "正在检查所有脚本的状态..."
- for script in "${SCRIPT_NAMES[@]}"; do
- status_script "$script"
- done
- ;;
- health)
- if [[ "$script_name" == "all" ]]; then
- local all_healthy=true
- for script in "${SCRIPT_NAMES[@]}"; do
- if ! health_check "$script"; then
- all_healthy=false
- fi
- done
- if [[ "$all_healthy" == true ]]; then
- log "INFO" "所有脚本健康检查通过"
- exit 0
- else
- log "ERROR" "部分脚本健康检查失败"
- exit 1
- fi
- elif get_script_file "$script_name" >/dev/null 2>&1; then
- if health_check "$script_name"; then
- log "INFO" "$script_name 健康检查通过"
- exit 0
- else
- log "ERROR" "$script_name 健康检查失败"
- exit 1
- fi
- else
- log "ERROR" "未知的脚本名称: $script_name"
- show_usage
- exit 1
- fi
- ;;
- info)
- get_system_info
- ;;
- *)
- log "ERROR" "未知命令: $command"
- show_usage
- exit 1
- ;;
- esac
- }
- # Run main function
- main "$@"
|