试点启用隔离 Rust 编译缓存并防止镜像叠层
Project CI / AI game creator shell Rust crates (pull_request) Successful in 1m23s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m34s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 9m23s
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Successful in 1m23s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m34s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 9m23s
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
仅在 AGC Rust lane 1 消费可信缓存快照,保持独立 target 和关闭增量编译 从远端 master 的确定提交构建快照,拒绝以已有对象缓存的镜像继续叠层 隔离缓存配置与进程状态,缓存故障回退真实编译并保留失败状态 增加命中统计、编译耗时和缓存行为验证 同步缓存来源、镜像保留及不中断运行中 CI 的运维约定
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/env bash
|
||||
# 仅消费镜像内的可信快照;所有写入留在当前容器的可写层。
|
||||
set -euo pipefail
|
||||
|
||||
cache_root="${GENARRATIVE_CI_RUST_CACHE_ROOT:-/opt/genarrative-ci/rust-cache}"
|
||||
cache_binary="${cache_root}/sccache"
|
||||
state="${GENARRATIVE_CI_RUST_CACHE_STATE:-}"
|
||||
|
||||
configure_local_cache() {
|
||||
# 不继承开发机/其它流水线的 OSS、S3、GHA 或 daemon 配置。
|
||||
local variable
|
||||
for variable in ${!SCCACHE_@}; do unset "${variable}"; done
|
||||
export SCCACHE_CONF="${state}/config"
|
||||
export SCCACHE_DIR="${cache_root}/objects"
|
||||
export SCCACHE_CACHE_SIZE=2G
|
||||
export SCCACHE_SERVER_UDS="${state}/server.sock"
|
||||
# 单个不可缓存的链接/测试阶段可能超过一分钟;保持统计直到 report 显式停止。
|
||||
export SCCACHE_IDLE_TIMEOUT=0
|
||||
export SCCACHE_IGNORE_SERVER_IO_ERROR=1
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
prepare)
|
||||
: "${GITHUB_ENV:?GITHUB_ENV is required}"
|
||||
printf 'RUSTC_WRAPPER=\nCARGO_BUILD_RUSTC_WRAPPER=\nGENARRATIVE_CI_RUST_CACHE_STATE=\n' >> "${GITHUB_ENV}"
|
||||
fallback() { printf '[rust-cache] mode=direct reason=%s\n' "$1"; exit 0; }
|
||||
[[ -x "${cache_binary}" && -d "${cache_root}/objects" && -f "${cache_root}/rustc.txt" && -f "${cache_root}/source-commit.txt" && -f "${cache_root}/workspace.txt" ]] \
|
||||
|| fallback snapshot-unavailable
|
||||
if ! rustc -vV | cmp -s - "${cache_root}/rustc.txt"; then
|
||||
fallback toolchain-mismatch
|
||||
fi
|
||||
if [[ "$(pwd -P)" != "$(cat "${cache_root}/workspace.txt")" ]]; then
|
||||
fallback workspace-mismatch
|
||||
fi
|
||||
# 使用短 Unix socket 路径,避免共享固定端口或超出 sockaddr_un 长度。
|
||||
state="$(mktemp -d /tmp/ci-rust-cache.XXXXXX)"
|
||||
printf 'server_startup_timeout_ms = 5000\n' > "${state}/config"
|
||||
configure_local_cache
|
||||
# 探测必须暴露 daemon 故障;只有正式编译允许 sccache 的 IO 回退。
|
||||
unset SCCACHE_IGNORE_SERVER_IO_ERROR
|
||||
if ! timeout --kill-after=2 15 "${cache_binary}" "$(command -v rustc)" -vV > "${state}/probe.log" 2>&1; then
|
||||
timeout --kill-after=2 5 "${cache_binary}" --stop-server >/dev/null 2>&1 || true
|
||||
rm -rf -- "${state}"
|
||||
fallback wrapper-probe-failed
|
||||
fi
|
||||
script_path="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)/$(basename "${BASH_SOURCE[0]}")"
|
||||
# wrapper 路径也参与 Rust cache key;固定容器内路径,隔离由 job 容器保证。
|
||||
wrapper_path="${cache_root}/rustc-wrapper"
|
||||
printf '#!/usr/bin/env bash\nexec bash %q "$@"\n' "${script_path}" > "${wrapper_path}"
|
||||
chmod 700 "${wrapper_path}"
|
||||
{
|
||||
printf 'GENARRATIVE_CI_RUST_CACHE_ROOT=%s\n' "${cache_root}"
|
||||
printf 'GENARRATIVE_CI_RUST_CACHE_STATE=%s\n' "${state}"
|
||||
printf 'RUSTC_WRAPPER=%s\nCARGO_BUILD_RUSTC_WRAPPER=%s\n' "${wrapper_path}" "${wrapper_path}"
|
||||
} >> "${GITHUB_ENV}"
|
||||
printf '[rust-cache] mode=sccache snapshot=%s\n' "$(cat "${cache_root}/source-commit.txt")"
|
||||
;;
|
||||
report)
|
||||
if [[ -n "${state}" && -d "${state}" ]]; then
|
||||
configure_local_cache
|
||||
timeout --kill-after=2 5 "${cache_binary}" --show-stats || true
|
||||
timeout --kill-after=2 5 "${cache_binary}" --stop-server >/dev/null 2>&1 || true
|
||||
rm -rf -- "${state}"
|
||||
else
|
||||
printf '[rust-cache] mode=direct\n'
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
# Cargo wrapper 协议:第一个参数是真实 rustc。失去缓存状态时仍执行原编译。
|
||||
if [[ -z "${state}" || ! -f "${state}/config" || -f "${state}/disabled" || ! -x "${cache_binary}" ]]; then
|
||||
exec "$@"
|
||||
fi
|
||||
configure_local_cache
|
||||
status=0
|
||||
"${cache_binary}" "$@" || status=$?
|
||||
if [[ "${status}" == 2 ]]; then
|
||||
# 固定 sccache 版本的自身错误码为 2;实际 rustc 失败通常为 1/101。
|
||||
# 只重试这次编译,不重跑 Cargo 或测试,真实编译错误仍按 rustc 状态返回。
|
||||
echo '[rust-cache] cache infrastructure failed; compiling directly' >&2
|
||||
# 后续 crate 直接编译,避免坏 daemon 让每个 crate 都支付一次启动超时。
|
||||
: > "${state}/disabled"
|
||||
exec "$@"
|
||||
fi
|
||||
exit "${status}"
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user