#!/usr/bin/env bash # M3R 缩尺批验 MasterProcess 包装器(systemd --user 单元 ExecStart 指向本脚本)。 # # 职责: # * 在 落 state.json(pid/unit/log/commit/workers/worlds/days/起止/exit); # * 以 2>&1 运行 Headless Release 批处理 `--batch `,逐世界流式; # * 进程退出即写回 ended_at 与退出码,并把真实退出码回传给 systemd。 # # 环境变量(由 unit 注入): # M3R_REPO 仓库根(绝对路径) # M3R_DIR 本次运行证据目录(绝对路径,state.json 落此) # M3R_COMMIT 期望 commit 短哈希(写入 state.json) # M3R_WORLDS 世界数(默认 50) # M3R_DAYS 模拟天数(默认 15) # LV_BATCH_WORKERS 并行 worker 数(默认 12) # M3R_LOG 验收日志路径(只写入 state.json 作为记录,实际重定向由 unit 负责) set -u REPO="${M3R_REPO:?M3R_REPO required}" DIR="${M3R_DIR:?M3R_DIR required}" COMMIT="${M3R_COMMIT:?M3R_COMMIT required}" WORLDS="${M3R_WORLDS:-50}" DAYS="${M3R_DAYS:-15}" WORKERS="${LV_BATCH_WORKERS:-12}" LOG="${M3R_LOG:-$REPO/artifacts/m3r-acceptance/acceptance.log}" UNIT="living-village-m3r.service" DLL="$REPO/src/LivingVillage.Headless/bin/Release/net8.0/LivingVillage.Headless.dll" mkdir -p "$DIR" if [ ! -f "$DLL" ]; then echo "[m3r] FATAL missing build: $DLL" >&2 exit 90 fi STARTED="$(date -u +%Y-%m-%dT%H:%M:%SZ)" echo "$$" > "$DIR/pid" echo "[m3r] start unit=$UNIT pid=$$ commit=$COMMIT workers=$WORKERS worlds=$WORLDS days=$DAYS started_at=$STARTED" python3 - "$DIR/state.json" "$UNIT" "$COMMIT" "$WORKERS" "$WORLDS" "$DAYS" "$LOG" "$STARTED" "$$" <<'PY' import json, sys out, unit, commit, workers, worlds, days, log, started, pid = sys.argv[1:10] state = { "pid": int(pid), "unit": unit, "log": log, "commit": commit, "workers": int(workers), "worlds": int(worlds), "days": int(days), "started_at": started, "ended_at": None, "exit": None, } with open(out, "w", encoding="utf-8") as fh: json.dump(state, fh, ensure_ascii=False, indent=2, sort_keys=True) fh.write("\n") PY export LV_BATCH_WORKERS="$WORKERS" ( exec dotnet "$DLL" --batch "$WORLDS" "$DAYS" 2>&1 ) CODE=$? ENDED="$(date -u +%Y-%m-%dT%H:%M:%SZ)" echo "[m3r] end pid=$$ exit=$CODE ended_at=$ENDED" python3 - "$DIR/state.json" "$CODE" "$ENDED" <<'PY' import json, sys path, code, ended = sys.argv[1:4] with open(path, encoding="utf-8") as fh: state = json.load(fh) state["ended_at"] = ended state["exit"] = int(code) with open(path, "w", encoding="utf-8") as fh: json.dump(state, fh, ensure_ascii=False, indent=2, sort_keys=True) fh.write("\n") PY exit "$CODE"