RomanCohort commited on
Commit
bcfd187
·
verified ·
1 Parent(s): 4a3a9f5

add scripts/_scratch/_retry_runner.py

Browse files
Files changed (1) hide show
  1. scripts/_scratch/_retry_runner.py +63 -0
scripts/_scratch/_retry_runner.py ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """自动重试跑一个命令,直到退出码为 0 或达到上限。
2
+
3
+ 为什么不用 PowerShell 包一层
4
+ ---------------------------
5
+ 试过了,**嵌套引号在 cmd → powershell → python 三层之间会被吃掉**,导致内层命令
6
+ 每次都以退出码 1 立刻失败(日志里能看到 attempt 2/30、3/30 都是秒退)。
7
+ Python 的 `subprocess` 收的是**参数列表**,不经过 shell 解析,没有这个坑。
8
+
9
+ 用法:
10
+ python scripts/_retry_runner.py --tries 30 --sleep 20 --log logs/x.log -- <命令> [参数...]
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import argparse
16
+ import subprocess
17
+ import sys
18
+ import time
19
+ from pathlib import Path
20
+
21
+
22
+ def main() -> int:
23
+ ap = argparse.ArgumentParser()
24
+ ap.add_argument("--tries", type=int, default=30)
25
+ ap.add_argument("--sleep", type=int, default=20)
26
+ ap.add_argument("--log", type=Path, default=None)
27
+ ap.add_argument("cmd", nargs=argparse.REMAINDER)
28
+ args = ap.parse_args()
29
+ cmd = args.cmd[1:] if args.cmd and args.cmd[0] == "--" else args.cmd
30
+ if not cmd:
31
+ print("[retry] 没给命令")
32
+ return 2
33
+
34
+ log = args.log
35
+ if log:
36
+ log.parent.mkdir(parents=True, exist_ok=True)
37
+
38
+ def note(msg: str) -> None:
39
+ line = f"[retry] {msg} {time.strftime('%Y-%m-%d %H:%M:%S')}"
40
+ print(line, flush=True)
41
+ if log:
42
+ with log.open("a", encoding="utf-8") as fh:
43
+ fh.write(line + "\n")
44
+
45
+ note("cmd = " + " ".join(cmd))
46
+ for i in range(1, args.tries + 1):
47
+ note(f"attempt {i}/{args.tries}")
48
+ try:
49
+ rc = subprocess.run(cmd, cwd=str(Path(__file__).resolve().parents[1])).returncode
50
+ except Exception as exc: # noqa: BLE001
51
+ note(f"spawn failed: {type(exc).__name__}: {exc}")
52
+ rc = -1
53
+ note(f"exit code {rc}")
54
+ if rc == 0:
55
+ note("completed successfully")
56
+ return 0
57
+ time.sleep(args.sleep)
58
+ note("gave up after max tries")
59
+ return 1
60
+
61
+
62
+ if __name__ == "__main__":
63
+ raise SystemExit(main())