Files
ai_Image_review/start_similarity.sh

489 lines
14 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# ============================================
# 图片去重审核系统管理脚本
# 支持进程数量控制
# ============================================
# 配置区
BASE_DIR="/home/work/ai_Image_review"
VENV_PYTHON="${BASE_DIR}/venv/bin/python"
# image_similarity_check 配置
CHECK_SCRIPT="${BASE_DIR}/image_similarity_check.py"
CHECK_PID_FILE="${BASE_DIR}/image_similarity_check.pid"
CHECK_LOG_FILE="${BASE_DIR}/image_similarity.log"
CHECK_MAX_PROCESSES=1 # 限制最多1个进程
# stats_similarity 配置(仅用于查看状态,不需要常驻进程)
STATS_SCRIPT="${BASE_DIR}/stats_similarity.py"
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 获取脚本正在运行的进程数量
get_process_count() {
local script_name=$(basename "$1")
pgrep -f "$script_name" 2>/dev/null | wc -l
}
# 获取所有相关进程的PID
get_all_pids() {
local script_name=$(basename "$1")
pgrep -f "$script_name" 2>/dev/null | tr '\n' ' '
}
# 启动单个服务(带进程数量控制)
start_single() {
local script=$1
local pid_file=$2
local log_file=$3
local name=$4
local max_processes=$5
local script_name=$(basename "$script")
local current_count=$(get_process_count "$script")
# 检查是否超过最大进程数
if [ $current_count -ge $max_processes ]; then
echo -e "${YELLOW}${name} 已达到最大进程数 (${current_count}/${max_processes}),跳过启动${NC}"
# 更新PID文件为第一个找到的PID
local first_pid=$(pgrep -f "$script_name" | head -n1)
if [ -n "$first_pid" ]; then
echo "$first_pid" > "$pid_file"
fi
return 0
fi
# 检查PID文件记录的进程
if [ -f "$pid_file" ]; then
local pid=$(cat "$pid_file" 2>/dev/null)
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null 2>&1; then
echo -e "${YELLOW}${name} 已在运行PID文件记录PID: ${pid}${NC}"
return 0
fi
fi
echo -e "${BLUE}正在启动 ${name}...${NC}"
# 确保日志目录存在
mkdir -p "$(dirname "$log_file")"
# 备份旧日志
if [ -f "$log_file" ]; then
local backup_log="${log_file}.$(date +%Y%m%d_%H%M%S).bak"
cp "$log_file" "$backup_log"
echo -e "${BLUE}旧日志已备份到: ${backup_log}${NC}"
fi
# 启动进程
nohup "$VENV_PYTHON" "$script" >> "$log_file" 2>&1 &
local new_pid=$!
# 等待进程真正启动
sleep 2
# 验证进程是否启动成功
if kill -0 "$new_pid" 2>/dev/null; then
echo "$new_pid" > "$pid_file"
echo -e "${GREEN}${name} 已启动PID: ${new_pid}${NC}"
echo -e "${BLUE}日志文件: ${log_file}${NC}"
return 0
else
echo -e "${RED}${name} 启动失败,请检查日志${NC}"
tail -20 "$log_file"
rm -f "$pid_file"
return 1
fi
}
# 停止单个服务的所有实例
stop_single_all() {
local script=$1
local name=$2
local pid_file=$3
local script_name=$(basename "$script")
local pids=$(get_all_pids "$script")
local count=$(get_process_count "$script")
if [ $count -eq 0 ]; then
echo -e "${YELLOW}${name} 没有运行中的进程${NC}"
rm -f "$pid_file"
return 0
fi
echo -e "${BLUE}正在停止 ${name} (${count}个进程)...${NC}"
echo -e "进程PIDs: ${pids}"
# 首先尝试优雅终止
for pid in $pids; do
if kill -0 "$pid" 2>/dev/null; then
echo -e " 发送SIGTERM到 PID $pid..."
kill "$pid"
fi
done
# 等待优雅退出
local wait_time=10
local remaining=$count
for i in $(seq 1 $wait_time); do
remaining=$(get_process_count "$script")
if [ $remaining -eq 0 ]; then
break
fi
echo -n "."
sleep 1
done
echo "" # 换行
# 检查是否还有进程残留
remaining=$(get_process_count "$script")
if [ $remaining -gt 0 ]; then
echo -e "${YELLOW}还有 ${remaining} 个进程未退出,强制终止...${NC}"
pids=$(get_all_pids "$script")
for pid in $pids; do
if kill -0 "$pid" 2>/dev/null; then
kill -9 "$pid" 2>/dev/null
fi
done
sleep 2
fi
# 验证所有进程都已停止
remaining=$(get_process_count "$script")
if [ $remaining -eq 0 ]; then
echo -e "${GREEN}${name} 所有进程已停止${NC}"
rm -f "$pid_file"
return 0
else
echo -e "${RED}警告:仍有 ${remaining} 个进程无法终止${NC}"
return 1
fi
}
# 启动所有服务
start() {
echo -e "${BLUE}========== 启动图片去重审核系统 ===========${NC}"
echo -e "${YELLOW}进程限制每个服务最多启动1个实例${NC}"
echo ""
# 检查总进程数
local total_before=$(pgrep -f "image_similarity_check" | wc -l)
if [ $total_before -gt 0 ]; then
echo -e "${YELLOW}当前已有 ${total_before} 个审核进程在运行${NC}"
echo -e "${YELLOW}建议先停止现有进程: $0 stop${NC}"
echo -e "${YELLOW}或强制重启: $0 force-restart${NC}"
return 1
fi
local has_errors=0
# 启动主处理脚本
if ! start_single "$CHECK_SCRIPT" "$CHECK_PID_FILE" "$CHECK_LOG_FILE" "image_similarity_check" "$CHECK_MAX_PROCESSES"; then
has_errors=1
fi
echo ""
# 检查启动结果
local total_after=$(pgrep -f "image_similarity_check" | wc -l)
if [ $has_errors -eq 0 ]; then
echo -e "${GREEN}✅ 启动完成,当前运行 ${total_after} 个进程${NC}"
else
echo -e "${YELLOW}⚠️ 启动完成,但有错误,当前运行 ${total_after} 个进程${NC}"
fi
echo -e "${BLUE}========================================${NC}"
}
# 只启动主脚本
start-check() {
echo -e "${BLUE}========== 启动主处理脚本 ===========${NC}"
start_single "$CHECK_SCRIPT" "$CHECK_PID_FILE" "$CHECK_LOG_FILE" "image_similarity_check" "$CHECK_MAX_PROCESSES"
echo -e "${BLUE}====================================${NC}"
}
# 停止所有服务
stop() {
echo -e "${BLUE}========== 停止图片去重审核系统 ===========${NC}"
local has_errors=0
local total_before=$(pgrep -f "image_similarity_check" | wc -l)
echo -e "${YELLOW}当前共有 ${total_before} 个审核进程${NC}"
# 停止主处理脚本
if ! stop_single_all "$CHECK_SCRIPT" "image_similarity_check" "$CHECK_PID_FILE"; then
has_errors=1
fi
# 最终检查
local total_after=$(pgrep -f "image_similarity_check" | wc -l)
echo ""
if [ $total_after -eq 0 ]; then
echo -e "${GREEN}✅ 所有审核进程已停止${NC}"
else
echo -e "${RED}❌ 仍有 ${total_after} 个进程无法停止${NC}"
has_errors=1
fi
echo -e "${BLUE}========================================${NC}"
return $has_errors
}
# 强制停止所有服务
force-stop() {
echo -e "${RED}========== 强制停止所有审核进程 ===========${NC}"
# 停止所有相关进程
pkill -9 -f "image_similarity_check.py" 2>/dev/null
sleep 2
# 清理PID文件
rm -f "${BASE_DIR}"/*.pid
# 检查是否还有残留
local remaining=$(pgrep -f "image_similarity_check" | wc -l)
if [ $remaining -eq 0 ]; then
echo -e "${GREEN}✅ 所有进程已强制停止${NC}"
else
echo -e "${RED}❌ 仍有 ${remaining} 个进程存活${NC}"
echo -e "请手动检查以下进程:"
pgrep -f "image_similarity_check" | xargs ps -fp 2>/dev/null
fi
echo -e "${RED}==========================================${NC}"
}
# 重启服务
restart() {
echo -e "${BLUE}========== 重启图片去重审核系统 ==========${NC}"
stop
if [ $? -eq 0 ]; then
sleep 3
start
else
echo -e "${RED}停止服务失败,请使用 force-restart${NC}"
return 1
fi
echo -e "${BLUE}========================================${NC}"
}
# 强制重启
force-restart() {
echo -e "${YELLOW}========== 强制重启图片去重审核系统 ==========${NC}"
force-stop
sleep 3
start
echo -e "${YELLOW}============================================${NC}"
}
# 显示统计信息
stats() {
echo -e "${BLUE}========== 图片去重统计报告 ==========${NC}"
"$VENV_PYTHON" "$STATS_SCRIPT"
echo -e "${BLUE}======================================${NC}"
}
# 显示详细状态
status() {
echo -e "${BLUE}========== 图片去重审核系统状态 ==========${NC}"
echo -e "${BLUE}系统时间: $(date)${NC}"
echo -e "${BLUE}工作目录: ${BASE_DIR}${NC}"
echo ""
local total_procs=$(pgrep -f "image_similarity_check" | wc -l)
echo -e "${YELLOW}📊 进程概览:${NC}"
echo -e " 总进程数: ${total_procs}"
if [ $total_procs -gt 0 ]; then
# 按脚本类型统计
declare -A script_count
declare -A script_cpu
declare -A script_mem
local cpu_sum=0
local mem_sum=0
# 收集所有进程信息
while read -r line; do
if [ -n "$line" ]; then
pid=$(echo $line | awk '{print $1}')
script_path=$(echo $line | awk '{print $NF}')
script_name=$(basename "$script_path")
((script_count[$script_name]++))
# 获取CPU和内存使用
cpu=$(ps -p $pid -o %cpu --no-headers 2>/dev/null | tr -d ' ' | head -1)
mem=$(ps -p $pid -o %mem --no-headers 2>/dev/null | tr -d ' ' | head -1)
if [[ "$cpu" =~ ^[0-9.]+$ ]]; then
script_cpu[$script_name]=$(echo "${script_cpu[$script_name]:-0} + $cpu" | bc)
cpu_sum=$(echo "$cpu_sum + $cpu" | bc)
fi
if [[ "$mem" =~ ^[0-9.]+$ ]]; then
script_mem[$script_name]=$(echo "${script_mem[$script_name]:-0} + $mem" | bc)
mem_sum=$(echo "$mem_sum + $mem" | bc)
fi
fi
done < <(pgrep -f "image_similarity_check" | xargs ps -o pid,cmd --no-headers 2>/dev/null)
# 显示每个脚本的统计
for script in "${!script_count[@]}"; do
count=${script_count[$script]}
cpu=${script_cpu[$script]:-0}
mem=${script_mem[$script]:-0}
echo -e "\n${YELLOW}${script}:${NC}"
echo -e " 进程数: ${count}"
echo -e " CPU使用: ${cpu}%"
echo -e " 内存使用: ${mem}%"
# 显示进程PID
pids=$(pgrep -f "$script" | tr '\n' ' ')
echo -e " 进程PIDs: ${pids}"
done
echo -e "\n${YELLOW}📈 总计:${NC}"
echo -e " 总CPU使用: ${cpu_sum}%"
echo -e " 总内存使用: ${mem_sum}%"
else
echo -e "${RED}没有运行中的审核进程${NC}"
fi
echo ""
echo -e "${YELLOW}📁 PID文件状态${NC}"
for pid_file in "$CHECK_PID_FILE"; do
if [ -f "$pid_file" ]; then
script_name=$(basename "$pid_file" .pid)
pid=$(cat "$pid_file" 2>/dev/null)
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
echo -e " ${GREEN}${script_name}.pid: 有效 (PID: $pid)${NC}"
else
echo -e " ${RED}${script_name}.pid: 无效或进程不存在${NC}"
fi
else
script_name=$(basename "$pid_file" .pid)
echo -e " ${YELLOW}${script_name}.pid: 不存在${NC}"
fi
done
echo ""
echo -e "${YELLOW}📝 最近日志:${NC}"
if [ -f "$CHECK_LOG_FILE" ]; then
echo -e "${BLUE}--- image_similarity.log (最后5行) ---${NC}"
tail -5 "$CHECK_LOG_FILE" 2>/dev/null
fi
echo -e "${BLUE}========================================${NC}"
}
# 查看日志
logs() {
local lines=${1:-50}
echo -e "${BLUE}========== 查看日志 (最后 ${lines} 行) ===========${NC}"
if [ -f "$CHECK_LOG_FILE" ]; then
echo -e "\n${YELLOW}--- image_similarity.log ---${NC}"
tail -$lines "$CHECK_LOG_FILE"
fi
echo -e "${BLUE}============================================${NC}"
}
# 实时查看日志
logs-follow() {
echo -e "${BLUE}========== 实时查看日志 (Ctrl+C 退出) ===========${NC}"
tail -f "$CHECK_LOG_FILE"
}
# 显示帮助
show_help() {
echo -e "${GREEN}图片去重审核系统管理脚本${NC}"
echo ""
echo -e "${YELLOW}当前配置:${NC}"
echo -e " 工作目录: ${BASE_DIR}"
echo -e " image_similarity_check: 最多 ${CHECK_MAX_PROCESSES} 个进程"
echo ""
echo -e "${BLUE}用法: $0 {命令}${NC}"
echo ""
echo -e "${GREEN}服务管理:${NC}"
echo -e " ${YELLOW}start${NC} 启动服务"
echo -e " ${YELLOW}stop${NC} 停止服务"
echo -e " ${YELLOW}force-stop${NC} 强制停止进程"
echo -e " ${YELLOW}restart${NC} 重启服务"
echo -e " ${YELLOW}force-restart${NC} 强制重启"
echo ""
echo -e "${GREEN}状态查看:${NC}"
echo -e " ${YELLOW}status${NC} 显示进程状态"
echo -e " ${YELLOW}stats${NC} 显示统计报告"
echo -e " ${YELLOW}logs [N]${NC} 查看最后N行日志(默认50)"
echo -e " ${YELLOW}logs-follow${NC} 实时查看日志"
echo ""
echo -e "${GREEN}其他:${NC}"
echo -e " ${YELLOW}help${NC} 显示帮助"
echo ""
echo -e "${RED}注意:${NC}"
echo -e " - 脚本会限制最多启动1个实例"
echo -e " - 处理 status='draft', similarity='draft' 的数据"
}
# 主逻辑
case "$1" in
start)
start
;;
start-check)
start-check
;;
stop)
stop
;;
force-stop)
force-stop
;;
restart)
restart
;;
force-restart)
force-restart
;;
status)
status
;;
stats)
stats
;;
logs)
logs $2
;;
logs-follow)
logs-follow
;;
help|--help|-h)
show_help
;;
*)
echo -e "${RED}错误:未知命令 '$1'${NC}"
echo ""
show_help
exit 1
;;
esac
exit 0