Skip to content

[Bug] docker_pull 的无参数 wait 可能陷入错误循环并写满日志 #21

Description

@lln556

问题描述

xiaoyakeeperdocker_pull() 在脚本已有长期后台任务时,可能在命令替换中的无参数 wait 处陷入高速错误循环:

/etc/xiaoya/aliyun_clear.sh: line 736: wait: pid 472 is not a child of this shell

该错误会被 Docker json-file 日志驱动持续写入磁盘。一次实际故障中,日志在约 68 分钟内增长到 17.1 GB,瞬时增长速度达到约 27 MB/s,险些写满系统盘。

环境

  • 脚本版本:202607301821
  • 镜像:ddsderek/xiaoyakeeper:latest
  • 镜像 ID:sha256:c68d27f0f2d7e56edbd5aa7a60daa463269779d41f47358c137459bf7c704c7e
  • Bash:5.3.3(1)-release (x86_64-alpine-linux-musl)
  • Docker Server:28.5.2

时间线

  • 2026-07-30 23:05:28:检测到并开始更新至 202607301821
  • 23:06:39:新版脚本开始运行
  • 23:08:13:首次出现 wait: pid ... is not a child of this shell
  • 2026-07-31 00:15:51:手动停止容器,此时日志为 17.1 GB

首次错误之前整个容器日志不足 1 MB,之后的空间增长几乎全部来自该错误循环。

最小复现

官方镜像中运行:

docker run --rm --entrypoint bash ddsderek/xiaoyakeeper:latest -c '
timeout 2 bash -c '\''
  sleep 30 &
  parent_bg=$!
  result=$(sleep 0.01 & wait)
  kill "$parent_bg" 2>/dev/null
'\'' 2>/tmp/wait.err
wc -c -l /tmp/wait.err
head -n 2 /tmp/wait.err
'

复现结果:2 秒内产生 388129 行、20766704 字节 stderr,进程无法自行结束:

bash: line 4: wait: pid 10 is not a child of this shell

原因分析

脚本会通过 start_push_proc 创建长期后台任务。docker_pull() 随后在命令替换子 shell 中启动多个后台 curl,并使用无参数 wait

mirrors="$(
    for line in $mirrors; do
        curl ... &
    done
    wait
)"

Bash 5.3.3 的该子 shell 会看到父 shell 的后台作业记录,但对应 PID 并不是它的子进程。无参数 wait 因而反复尝试等待该 PID并持续报错。

建议修复

只记录这一批测速 curl 的 PID,并逐个显式等待:

pids=""
for line in $mirrors; do
    curl ... &
    pids="$pids $!"
done
for pid in $pids; do
    wait "$pid"
done

相同环境的验证结果:显式 PID 版本正常退出,stderr 为 0;同时保留并发测速行为。

另外建议为容器配置日志轮转作为第二层保护,但这不能替代脚本死循环修复。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions