Files
hzdyjs/退学、休学、复学、毕业/control_scripts.sh
T
2025-12-26 00:44:19 +08:00

482 lines
14 KiB
Bash
Executable File

#!/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 "$@"