Preserve rollback artifacts across same-second deployments
Why: Second-resolution release IDs let staging delete a previous release when a same-source deployment ran within the same clock tick. Evidence: Fixed-clock rollback regression fails before and passes after; 250 governance checks pass. Independent review replays collision and copy-failure protection; receipts are in the primary task card. Impact: Add invocation identity and exclusive directory creation; keep old artifacts intact. Also retain the latest compatible frontend pointer. Refs: User-approved I2; Dev #483; Frontend #71/#72
This commit is contained in:
File diff suppressed because one or more lines are too long
+1
-1
Submodule modules/frontend updated: 3a5fbe6e42...4965de269a
+6
-4
@@ -1641,11 +1641,11 @@ svc_release_adopt_legacy() {
|
||||
c_info "[$ENV_NAME] 领养 legacy 制品为首个 release:releases/$id"
|
||||
}
|
||||
|
||||
# svc_release_id:源标签净化的版本目录名(rdm-ddc09eb-20261012T131500)。
|
||||
# svc_release_id:源标签 + 时钟 + 调用进程身份,同源同秒部署仍使用不同目录。
|
||||
svc_release_id() {
|
||||
local label
|
||||
label="$(printf '%s' "${SRC_LABEL:-manual}" | tr '@' '-' | tr -cd 'a-zA-Z0-9._-' | cut -c1-40)"
|
||||
printf '%s-%s' "$label" "$(date -u +%Y%m%dT%H%M%SZ)"
|
||||
printf '%s-%s-%s' "$label" "$(date -u +%Y%m%dT%H%M%SZ)" "$BASHPID"
|
||||
}
|
||||
|
||||
# svc_release_stage ID SRCBIN SRCPLUGINS [HTDOCS]:候选产物入不可变版本目录。
|
||||
@@ -1653,8 +1653,10 @@ svc_release_id() {
|
||||
svc_release_stage() {
|
||||
local id="$1" srcbin="$2" srcplug="$3" htdocs="${4:-}"
|
||||
local dir="$ENV_DIR/releases/$id"
|
||||
rm -rf "$dir"
|
||||
mkdir -p "$dir/bin" || return 1
|
||||
mkdir -p "$ENV_DIR/releases" || return 1
|
||||
# 排他创建:重复 id 必须拒绝,不能覆盖仍用于运行或回退的历史制品。
|
||||
mkdir "$dir" || { c_err "[$ENV_NAME] release 目录已存在或无法创建:$dir"; return 1; }
|
||||
mkdir "$dir/bin" || return 1
|
||||
cp -f "$srcbin" "$dir/bin/agent-system" || return 1
|
||||
if [ -d "$srcplug" ]; then
|
||||
cp -r "$srcplug" "$dir/plugins" || return 1
|
||||
|
||||
@@ -9,6 +9,7 @@ tests/test_svc_identity.py(IdentityTests:manifest 治理 + 源仓轨道 + no
|
||||
import importlib.util
|
||||
import json
|
||||
import os
|
||||
import shlex
|
||||
import shutil
|
||||
import subprocess
|
||||
import unittest
|
||||
@@ -89,6 +90,21 @@ class U2ReleaseTests(tsi.IdentityTests):
|
||||
# ---- T1:release 布局 + 启动失败回退 + 期望态恢复 ----
|
||||
|
||||
def test_U2_layout_switch_and_rollback_on_start_failure(self):
|
||||
# Both deployments intentionally share the same clock tick: a failed
|
||||
# candidate must never overwrite the version needed for rollback.
|
||||
clock_bin = self.root / "fixed-clock"
|
||||
clock_bin.mkdir()
|
||||
real_date = shutil.which("date")
|
||||
clock = clock_bin / "date"
|
||||
clock.write_text(
|
||||
'#!/bin/bash\n'
|
||||
'if [[ "$*" == *"+%Y%m%dT%H%M%SZ"* ]]; then\n'
|
||||
' echo 20261012T120000Z\n'
|
||||
'else\n'
|
||||
f' exec {shlex.quote(real_date)} "$@"\n'
|
||||
'fi\n')
|
||||
clock.chmod(0o755)
|
||||
self.env["PATH"] = str(clock_bin) + os.pathsep + self.env["PATH"]
|
||||
self.make_src_repo() # 预克隆 srccache(本用例走 --from local,仅保环境一致)
|
||||
self.seed_agent("u2a", 9461)
|
||||
self.start_ok("u2a") # legacy 运行中(期望态=running)
|
||||
|
||||
Reference in New Issue
Block a user