java-deploy.sh 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. #!/bin/bash
  2. # ============================================
  3. # 中华药典 AI Agent — Java 后端部署脚本
  4. # 用法: ./java-deploy.sh {start|stop|restart|status|logs|build|deploy|rollback}
  5. # ============================================
  6. set -e
  7. APP_DIR="/opt/pharmacopoeia-ai/backend-java"
  8. PROJECT_DIR="/opt/pharmacopoeia-ai"
  9. JAR_FILE="$APP_DIR/target/pharmacopoeia-ai-1.0.0.jar"
  10. LOG_DIR="/var/log/pharmacopoeia"
  11. PID_FILE="$APP_DIR/app.pid"
  12. # 加载 .env 环境变量
  13. load_env() {
  14. if [ -f "$PROJECT_DIR/.env" ]; then
  15. set -a
  16. source "$PROJECT_DIR/.env"
  17. set +a
  18. fi
  19. }
  20. load_env
  21. mkdir -p "$LOG_DIR"
  22. # ---- 服务端口 ----
  23. PORT=${SERVER_PORT:-9000}
  24. HEALTH_URL="http://localhost:${PORT}/health"
  25. # ============================================
  26. # 通用函数
  27. # ============================================
  28. running() {
  29. [ -f "$PID_FILE" ] && kill -0 "$(cat "$PID_FILE")" 2>/dev/null
  30. }
  31. get_pid() {
  32. cat "$PID_FILE" 2>/dev/null || echo "N/A"
  33. }
  34. health_check() {
  35. curl -sf "$HEALTH_URL" > /dev/null 2>&1
  36. }
  37. # ============================================
  38. # 启动
  39. # ============================================
  40. start() {
  41. if running; then
  42. echo "⚠️ 后端已在运行中 (PID: $(get_pid))"
  43. curl -sf "$HEALTH_URL" | python3 -m json.tool 2>/dev/null || true
  44. return 0
  45. fi
  46. # 自动编译(如果 JAR 不存在)
  47. if [ ! -f "$JAR_FILE" ]; then
  48. echo "📦 JAR 不存在,正在编译..."
  49. cd "$APP_DIR"
  50. mvn clean package -DskipTests -q
  51. echo "✅ 编译完成"
  52. fi
  53. echo "🚀 启动后端..."
  54. cd "$APP_DIR"
  55. JVM_OPTS="-Xms512m -Xmx2g"
  56. JVM_OPTS="$JVM_OPTS -XX:+UseG1GC"
  57. JVM_OPTS="$JVM_OPTS -Dfile.encoding=UTF-8"
  58. JVM_OPTS="$JVM_OPTS -Djava.security.egd=file:/dev/./urandom"
  59. nohup java $JVM_OPTS -jar "$JAR_FILE" \
  60. --server.port="$PORT" \
  61. >> "$LOG_DIR/backend.log" 2>&1 &
  62. echo $! > "$PID_FILE"
  63. echo " PID: $(get_pid)"
  64. # 等启动完成
  65. echo -n " 等待启动"
  66. for i in $(seq 1 30); do
  67. if health_check 2>/dev/null; then
  68. echo ""
  69. echo "✅ 启动成功!"
  70. curl -sf "$HEALTH_URL" | python3 -m json.tool 2>/dev/null || true
  71. return 0
  72. fi
  73. echo -n "."
  74. sleep 1
  75. done
  76. echo ""
  77. echo "❌ 启动超时,查看日志:"
  78. tail -30 "$LOG_DIR/backend.log"
  79. rm -f "$PID_FILE"
  80. return 1
  81. }
  82. # ============================================
  83. # 停止
  84. # ============================================
  85. stop() {
  86. if ! running; then
  87. echo "后端未运行"
  88. rm -f "$PID_FILE"
  89. return 0
  90. fi
  91. PID=$(get_pid)
  92. echo "🛑 停止后端 (PID: $PID)..."
  93. kill "$PID"
  94. for i in $(seq 1 30); do
  95. if ! kill -0 "$PID" 2>/dev/null; then
  96. echo "✅ 已停止"
  97. rm -f "$PID_FILE"
  98. return 0
  99. fi
  100. sleep 1
  101. done
  102. echo "⚠️ 超时,强制终止..."
  103. kill -9 "$PID" 2>/dev/null || true
  104. rm -f "$PID_FILE"
  105. echo "✅ 已强制停止"
  106. }
  107. # ============================================
  108. # 重启
  109. # ============================================
  110. restart() {
  111. echo "⏳ 重启后端..."
  112. stop
  113. sleep 2
  114. start
  115. }
  116. # ============================================
  117. # 状态
  118. # ============================================
  119. status() {
  120. echo "========================================"
  121. echo " 中华药典 AI — Java 后端"
  122. echo "========================================"
  123. if running; then
  124. echo " 状态: ✅ 运行中"
  125. echo " PID: $(get_pid)"
  126. echo " 端口: $PORT"
  127. echo ""
  128. curl -sf "$HEALTH_URL" | python3 -m json.tool 2>/dev/null || echo " (健康检查无响应)"
  129. else
  130. echo " 状态: ❌ 未运行"
  131. fi
  132. echo ""
  133. echo " 日志: $LOG_DIR/backend.log"
  134. echo "========================================"
  135. }
  136. # ============================================
  137. # 日志
  138. # ============================================
  139. logs() {
  140. if [ "$1" = "-f" ]; then
  141. tail -f "$LOG_DIR/backend.log"
  142. else
  143. echo "=== 最近 100 行日志 ==="
  144. tail -${1:-100} "$LOG_DIR/backend.log"
  145. fi
  146. }
  147. # ============================================
  148. # 编译
  149. # ============================================
  150. build() {
  151. echo "📦 拉取最新代码..."
  152. cd "$PROJECT_DIR"
  153. git pull
  154. echo "🔨 编译打包..."
  155. cd "$APP_DIR"
  156. mvn clean package -DskipTests -q
  157. if [ -f "$JAR_FILE" ]; then
  158. echo "✅ 编译成功: $JAR_FILE"
  159. ls -lh "$JAR_FILE"
  160. else
  161. echo "❌ 编译失败"
  162. return 1
  163. fi
  164. }
  165. # ============================================
  166. # 一键部署(拉代码 → 编译 → 备份 → 重启)
  167. # ============================================
  168. deploy() {
  169. echo "========================================"
  170. echo " 一键部署"
  171. echo "========================================"
  172. echo ""
  173. echo "📥 拉取代码..."
  174. cd "$PROJECT_DIR"
  175. git pull
  176. echo ""
  177. echo "🔨 编译打包..."
  178. cd "$APP_DIR"
  179. mvn clean package -DskipTests -q
  180. if [ ! -f "$JAR_FILE" ]; then
  181. echo "❌ 编译失败,取消部署"
  182. return 1
  183. fi
  184. echo "✅ 编译完成: $(ls -lh "$JAR_FILE" | awk '{print $5}')"
  185. # 备份当前 JAR
  186. BACKUP_DIR="$APP_DIR/backups"
  187. mkdir -p "$BACKUP_DIR"
  188. if [ -f "$JAR_FILE" ]; then
  189. BACKUP_FILE="$BACKUP_DIR/pharmacopoeia-ai-$(date +%Y%m%d-%H%M%S).jar"
  190. cp "$JAR_FILE" "$BACKUP_FILE"
  191. echo "📦 已备份: $BACKUP_FILE"
  192. # 保留最近 5 个备份
  193. ls -t "$BACKUP_DIR"/*.jar 2>/dev/null | tail -n +6 | xargs rm -f 2>/dev/null || true
  194. fi
  195. echo ""
  196. restart
  197. }
  198. # ============================================
  199. # 回滚
  200. # ============================================
  201. rollback() {
  202. BACKUP_DIR="$APP_DIR/backups"
  203. if [ ! -d "$BACKUP_DIR" ] || [ -z "$(ls -A "$BACKUP_DIR" 2>/dev/null)" ]; then
  204. echo "❌ 没有可用的备份"
  205. return 1
  206. fi
  207. echo "可用备份:"
  208. ls -lht "$BACKUP_DIR"/*.jar 2>/dev/null | head -10
  209. echo ""
  210. if [ -n "$1" ]; then
  211. ROLLBACK_FILE="$1"
  212. else
  213. ROLLBACK_FILE=$(ls -t "$BACKUP_DIR"/*.jar 2>/dev/null | head -1)
  214. echo "回滚到最新备份: $(basename "$ROLLBACK_FILE")"
  215. fi
  216. if [ ! -f "$ROLLBACK_FILE" ]; then
  217. echo "❌ 备份文件不存在: $ROLLBACK_FILE"
  218. return 1
  219. fi
  220. echo ""
  221. echo "⏪ 回滚..."
  222. cp "$ROLLBACK_FILE" "$JAR_FILE"
  223. echo "✅ 已替换为: $(basename "$ROLLBACK_FILE")"
  224. restart
  225. }
  226. # ============================================
  227. # 入口
  228. # ============================================
  229. case "${1:-start}" in
  230. start) start ;;
  231. stop) stop ;;
  232. restart) restart ;;
  233. status) status ;;
  234. logs) logs "${2:-100}" ;;
  235. logf) logs -f ;;
  236. build) build ;;
  237. deploy) deploy ;;
  238. rollback) rollback "$2" ;;
  239. help|--help|-h)
  240. echo "用法: $0 {start|stop|restart|status|logs|logf|build|deploy|rollback}"
  241. echo ""
  242. echo " start 启动后端"
  243. echo " stop 停止后端"
  244. echo " restart 重启后端"
  245. echo " status 查看状态"
  246. echo " logs 查看最近 100 行日志"
  247. echo " logf 实时跟踪日志"
  248. echo " build 拉代码 + 编译"
  249. echo " deploy 拉代码 + 编译 + 备份 + 重启(一键上线)"
  250. echo " rollback 回滚到上一个备份(可指定备份文件路径)"
  251. exit 0
  252. ;;
  253. *)
  254. echo "用法: $0 {start|stop|restart|status|logs|logf|build|deploy|rollback}"
  255. exit 1
  256. ;;
  257. esac