From 371be8034d3e12b0a180bea729f9267f1145028d Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Wed, 16 Sep 2026 00:17:58 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix(ci):=20trap=20EXIT=20=E5=9B=9E=E6=94=B6?= =?UTF-8?q?=E9=9B=86=E6=88=90=E6=B5=8B=E8=AF=95=20PG/Redis=20=E5=AE=B9?= =?UTF-8?q?=E5=99=A8=EF=BC=8C=E6=9D=9C=E7=BB=9D=E5=8F=96=E6=B6=88/?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5=E6=97=B6=E6=B3=84=E6=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题:run_integration_tests.sh 用 docker run -d 起 ci-pg-/ci-redis- 服务容器, 仅在脚本正常走到结尾时 rm;job 失败(set -e)或被 Gitea 取消(SIGTERM)时容器 永久残留。2026-09-15 堆积 20 个泄漏容器把构建机 load 顶到 25.9,CI 大面积排队。 修复:参照 validate_migration.sh 既有做法,新增幂等 cleanup_containers 并注册 trap EXIT/INT/TERM,在启动服务容器前生效,保证任何退出路径都回收临时容器; 共享 PG 模式的 drop-db 逻辑保持不变。主机侧另有 ci_service_reaper.py 每5分钟兜底。 --- scripts/ci/run_integration_tests.sh | 33 +++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/scripts/ci/run_integration_tests.sh b/scripts/ci/run_integration_tests.sh index 1d05d85bd..3573c9bd8 100755 --- a/scripts/ci/run_integration_tests.sh +++ b/scripts/ci/run_integration_tests.sh @@ -120,6 +120,29 @@ wait_tcp_ready() { return 1 } +# --- 幂等容器清理(无论成功/失败/被取消都回收临时 PG、Redis,杜绝泄漏)--- +# 背景:服务容器用 docker run -d 起在宿主机上,仅在脚本走到结尾时清理; +# job 失败(set -e)或被取消(SIGTERM)时会永久残留,堆积压垮构建机。 +cleanup_containers() { + # 清理过程自身不能再次触发退出,避免掩盖原始退出码 + set +e + if [ -n "${PG_CONTAINER:-}" ]; then + docker rm -f "$PG_CONTAINER" >/dev/null 2>&1 && echo "✅ 已清理PG容器: $PG_CONTAINER" + fi + if [ -n "${REDIS_CONTAINER:-}" ]; then + docker rm -f "$REDIS_CONTAINER" >/dev/null 2>&1 && echo "✅ 已清理Redis容器: $REDIS_CONTAINER" + fi +} +on_exit() { + local code=$? + cleanup_containers + exit "$code" +} +# 必须在启动任何服务容器之前注册;INT/TERM 覆盖 Gitea 取消任务场景 +trap on_exit EXIT +trap 'exit 130' INT +trap 'exit 143' TERM + # --- 启动 Redis --- echo "" echo "=== 启动 Redis ===" @@ -302,14 +325,10 @@ conn.close() " 2>/dev/null || echo "WARN: 数据库清理失败(可能已被清理)" echo "✅ 共享PG数据库已清理" else - # 清理临时PG容器 - docker rm -f "$PG_CONTAINER" 2>/dev/null || true - echo "✅ PG容器已清理" + # 临时PG容器由 EXIT trap 的 cleanup_containers 统一回收(失败/取消也保证清理) + : fi - -# 清理Redis容器 -docker rm -f "$REDIS_CONTAINER" 2>/dev/null || true -echo "✅ Redis容器已清理" +# 临时Redis容器同样由 EXIT trap 统一回收 # --- 覆盖率汇总 --- echo "" From de56a674577e321adfdb9023df73f126e5dc1c0b Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Wed, 16 Sep 2026 00:19:06 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix(ci):=20run=5Fstaging=5Ftests.sh=20?= =?UTF-8?q?=E5=90=8C=E6=A0=B7=E5=8A=A0=20trap=20EXIT=20=E5=9B=9E=E6=94=B6?= =?UTF-8?q?=20staging=20=E6=B5=8B=E8=AF=95=E5=AE=B9=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/ci/run_staging_tests.sh | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/scripts/ci/run_staging_tests.sh b/scripts/ci/run_staging_tests.sh index dda2144ae..7b8d06ffd 100755 --- a/scripts/ci/run_staging_tests.sh +++ b/scripts/ci/run_staging_tests.sh @@ -16,6 +16,17 @@ CONTAINER_NAME="staging-${MODE}-$$" # 强制清理可能残留的同名容器 docker rm -f "$CONTAINER_NAME" 2>/dev/null || true +# 任何退出路径(成功/失败/被取消 SIGTERM)都回收容器,杜绝 staging 测试容器泄漏 +cleanup_container() { + local code=$? + set +e + docker rm -f "$CONTAINER_NAME" >/dev/null 2>&1 && echo "✅ 已清理容器: $CONTAINER_NAME" + exit "$code" +} +trap cleanup_container EXIT +trap 'exit 130' INT +trap 'exit 143' TERM + if [ "$MODE" = "e2e" ]; then docker create --name "$CONTAINER_NAME" --ipc=host \ -e E2E_BASE_URL=https://staging.xiaoxiajianji.com \ @@ -44,7 +55,5 @@ docker cp apps "$CONTAINER_NAME:/workspace/" docker start -a "$CONTAINER_NAME" EXIT_CODE=$(docker wait "$CONTAINER_NAME") -# 清理容器 -docker rm "$CONTAINER_NAME" 2>/dev/null || true - +# 容器由 EXIT trap 的 cleanup_container 统一回收(失败/取消也保证清理) exit "$EXIT_CODE"