You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker容器中JAR运行脚本无法捕获错误退出码问题

解决Docker容器中JAR启动脚本的退出码检测失效问题

问题背景

我在Docker容器中实现了一个JAR运行脚本,功能是读取Docker卷指定目录下的所有JAR文件,依次以后台进程启动。需求是如果JAR文件启动失败,要在控制台显示错误并记录退出码。

原脚本(run-jars.sh)

number_of_jars=$(find "$JAR_HOME" -maxdepth 1 -type f -name "*.jar" | wc -l)
printf "%s | [DEBUG] JAR files in the %s directory: %s\n" "$(date +"%Y-%b-%d %H:%M:%S")" "$JAR_HOME" "$number_of_jars"

for jar_file in "$JAR_HOME"/*.jar; do
   printf "%s | [INFO]  starting %s at the background...\n" "$(date +"%Y-%b-%d %H:%M:%S")" "$jar_file"
   nohup java -jar "$jar_file" 2>&1 &

   exit_code=$?
   pid=$!
   printf "%s | [DEBUG] PID       of the %s is %s\n" "$(date +"%Y-%b-%d %H:%M:%S")" "$jar_file" "$pid"
   printf "%s | [DEBUG] Exit code of the %s is %s\n" "$(date +"%Y-%b-%d %H:%M:%S")" "$jar_file" "$exit_code"

   timeout 5 tail --pid=$pid -f /dev/null
   exit_code=$?
   printf "%s | [DEBUG] Exit code of the %s is %s\n" "$(date +"%Y-%b-%d %H:%M:%S")" "$jar_file" "$exit_code"
   if [ "$exit_code" -ne 0 ]; then
      printf "%s | [ERROR] Java application %s exited with an error: %s" "$(date +"%Y-%b-%d %H:%M:%S")" "$jar_file" "$exit_code"
   fi
done

当前问题

脚本可正常启动JAR文件,但错误退出码检测失效:即使使用损坏的JAR文件,获取到的退出码始终为0。运行日志如下:

2024-Mar-03 13:38:24 | [DEBUG] JAR files in the /jars-to-run directory: 2
2024-Mar-03 13:38:24 | [INFO]  running /jars-to-run/aa.jar at the background...
Error: Invalid or corrupt jarfile /jars-to-run/aa.jar
2024-Mar-03 13:38:24 | [DEBUG] PID       of the /jars-to-run/aa.jar is 139
2024-Mar-03 13:38:24 | [DEBUG] Exit code of the /jars-to-run/aa.jar is 0
2024-Mar-03 13:38:24 | [DEBUG] Exit code of the /jars-to-run/aa.jar is 0
2024-Mar-03 13:38:24 | [INFO]  running /jars-to-run/rest-template-0.0.2.jar at the background...
2024-Mar-03 13:38:24 | [DEBUG] PID       of the /jars-to-run/rest-template-0.0.2.jar is 146
2024-Mar-03 13:38:24 | [DEBUG] Exit code of the /jars-to-run/rest-template-0.0.2.jar is 0

问题根源

  1. nohup的退出码干扰:nohup java -jar ... &执行后,$?获取的是nohup命令本身的退出码,而非Java进程的。只要nohup成功启动,就返回0,完全无法捕获Java启动失败的错误。
  2. timeout的退出码不反映实际进程状态:timeout 5 tail --pid=$pid -f /dev/null的退出码是timeout自身的:5秒内进程未退出则返回124,进程退出则返回0,和Java进程的实际退出码无关。

修复后的脚本

number_of_jars=$(find "$JAR_HOME" -maxdepth 1 -type f -name "*.jar" | wc -l)
printf "%s | [DEBUG] JAR files in the %s directory: %s\n" "$(date +"%Y-%b-%d %H:%M:%S")" "$JAR_HOME" "$number_of_jars"

for jar_file in "$JAR_HOME"/*.jar; do
    # 跳过非文件(避免无匹配jar时通配符被当作文件名)
    [ -f "$jar_file" ] || continue

    printf "%s | [INFO]  starting %s at the background...\n" "$(date +"%Y-%b-%d %H:%M:%S")" "$jar_file"
    
    # 启动Java进程,输出定向到单独的nohup日志
    nohup java -jar "$jar_file" > "${jar_file}.nohup.out" 2>&1 &
    pid=$!

    # 等待进程退出或超时5秒,获取真实退出码
    (wait "$pid"; echo $?) > "${jar_file}.exitcode" &
    sleep 5
    exit_code=$(cat "${jar_file}.exitcode" 2>/dev/null || echo 124)
    rm -f "${jar_file}.exitcode"

    printf "%s | [DEBUG] PID       of the %s is %s\n" "$(date +"%Y-%b-%d %H:%M:%S")" "$jar_file" "$pid"
    printf "%s | [DEBUG] Exit code of the %s is %s\n" "$(date +"%Y-%b-%d %H:%M:%S")" "$jar_file" "$exit_code"

    if [ "$exit_code" -ne 0 ] && [ "$exit_code" -ne 124 ]; then
        printf "%s | [ERROR] Java application %s exited with an error: %s\n" "$(date +"%Y-%b-%d %H:%M:%S")" "$jar_file" "$exit_code"
        # 可选:打印错误日志内容
        # printf "%s | [ERROR] Error details:\n" "$(date +"%Y-%b-%d %H:%M:%S")"
        # cat "${jar_file}.nohup.out"
    elif [ "$exit_code" -eq 124 ]; then
        printf "%s | [INFO]  Java application %s is running in background (timeout reached)\n" "$(date +"%Y-%b-%d %H:%M:%S")" "$jar_file"
    fi
done

修复说明

  • 捕获真实退出码:通过后台wait进程获取Java进程的退出码并写入临时文件,等待5秒后读取该文件,既避免无限等待,又能拿到进程的真实退出状态。
  • 单独日志文件:将每个JAR的输出定向到${jar_file}.nohup.out,方便后续排查启动失败的具体原因。
  • 处理无JAR场景:添加[ -f "$jar_file" ] || continue,防止目录下没有JAR文件时,通配符被当作无效文件名处理。
  • 区分超时和错误:退出码124表示进程在5秒内未退出(正常运行),其他非0值则标记为启动失败。

内容的提问来源于stack exchange,提问作者zappee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 14:47:13