vibego 0.2.42__py3-none-any.whl → 0.2.43__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of vibego might be problematic. Click here for more details.
- master.py +62 -40
- scripts/master_healthcheck.py +7 -3
- scripts/start.sh +14 -9
- scripts/stop_all.sh +6 -2
- {vibego-0.2.42.dist-info → vibego-0.2.43.dist-info}/METADATA +1 -1
- {vibego-0.2.42.dist-info → vibego-0.2.43.dist-info}/RECORD +10 -10
- vibego_cli/__init__.py +1 -1
- {vibego-0.2.42.dist-info → vibego-0.2.43.dist-info}/WHEEL +0 -0
- {vibego-0.2.42.dist-info → vibego-0.2.43.dist-info}/entry_points.txt +0 -0
- {vibego-0.2.42.dist-info → vibego-0.2.43.dist-info}/top_level.txt +0 -0
master.py
CHANGED
|
@@ -85,6 +85,11 @@ def _get_restart_signal_path() -> Path:
|
|
|
85
85
|
|
|
86
86
|
|
|
87
87
|
RESTART_SIGNAL_PATH = _get_restart_signal_path()
|
|
88
|
+
LEGACY_RESTART_SIGNAL_PATHS: Tuple[Path, ...] = tuple(
|
|
89
|
+
path
|
|
90
|
+
for path in (ROOT_DIR / "state/restart_signal.json",)
|
|
91
|
+
if path != RESTART_SIGNAL_PATH
|
|
92
|
+
)
|
|
88
93
|
RESTART_SIGNAL_TTL = int(os.environ.get("MASTER_RESTART_SIGNAL_TTL", "1800")) # 默认 30 分钟
|
|
89
94
|
LOCAL_TZ = ZoneInfo(os.environ.get("MASTER_TIMEZONE", "Asia/Shanghai"))
|
|
90
95
|
JUMP_BUTTON_TEXT_WIDTH = 40
|
|
@@ -1699,48 +1704,57 @@ def _write_restart_signal(message: Message, *, override_user: Optional[User] = N
|
|
|
1699
1704
|
)
|
|
1700
1705
|
|
|
1701
1706
|
|
|
1702
|
-
def _read_restart_signal() -> Optional[dict]:
|
|
1703
|
-
"""读取并验证重启 signal
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
if not isinstance(raw, dict):
|
|
1709
|
-
raise ValueError("signal payload 必须是对象")
|
|
1710
|
-
except Exception as exc:
|
|
1711
|
-
log.error("读取重启信号失败: %s", exc)
|
|
1712
|
-
_safe_remove(RESTART_SIGNAL_PATH)
|
|
1713
|
-
return None
|
|
1714
|
-
|
|
1715
|
-
timestamp_raw = raw.get("timestamp")
|
|
1716
|
-
if timestamp_raw:
|
|
1707
|
+
def _read_restart_signal() -> Tuple[Optional[dict], Optional[Path]]:
|
|
1708
|
+
"""读取并验证重启 signal,兼容历史路径并处理异常/超时情况"""
|
|
1709
|
+
candidates: Tuple[Path, ...] = (RESTART_SIGNAL_PATH, *LEGACY_RESTART_SIGNAL_PATHS)
|
|
1710
|
+
for path in candidates:
|
|
1711
|
+
if not path.exists():
|
|
1712
|
+
continue
|
|
1717
1713
|
try:
|
|
1718
|
-
|
|
1719
|
-
if
|
|
1720
|
-
|
|
1721
|
-
ts_utc = ts.astimezone(timezone.utc)
|
|
1722
|
-
age_seconds = (datetime.now(timezone.utc) - ts_utc).total_seconds()
|
|
1723
|
-
if age_seconds > RESTART_SIGNAL_TTL:
|
|
1724
|
-
log.info(
|
|
1725
|
-
"重启信号超时,忽略",
|
|
1726
|
-
extra={
|
|
1727
|
-
"path": str(RESTART_SIGNAL_PATH),
|
|
1728
|
-
"age_seconds": age_seconds,
|
|
1729
|
-
"ttl": RESTART_SIGNAL_TTL,
|
|
1730
|
-
},
|
|
1731
|
-
)
|
|
1732
|
-
_safe_remove(RESTART_SIGNAL_PATH)
|
|
1733
|
-
return None
|
|
1714
|
+
raw = json.loads(path.read_text(encoding="utf-8"))
|
|
1715
|
+
if not isinstance(raw, dict):
|
|
1716
|
+
raise ValueError("signal payload 必须是对象")
|
|
1734
1717
|
except Exception as exc:
|
|
1735
|
-
log.
|
|
1718
|
+
log.error("读取重启信号失败: %s", exc, extra={"path": str(path)})
|
|
1719
|
+
_safe_remove(path)
|
|
1720
|
+
continue
|
|
1736
1721
|
|
|
1737
|
-
|
|
1722
|
+
timestamp_raw = raw.get("timestamp")
|
|
1723
|
+
if timestamp_raw:
|
|
1724
|
+
try:
|
|
1725
|
+
ts = datetime.fromisoformat(timestamp_raw)
|
|
1726
|
+
if ts.tzinfo is None:
|
|
1727
|
+
ts = ts.replace(tzinfo=LOCAL_TZ)
|
|
1728
|
+
ts_utc = ts.astimezone(timezone.utc)
|
|
1729
|
+
age_seconds = (datetime.now(timezone.utc) - ts_utc).total_seconds()
|
|
1730
|
+
if age_seconds > RESTART_SIGNAL_TTL:
|
|
1731
|
+
log.info(
|
|
1732
|
+
"重启信号超时,忽略",
|
|
1733
|
+
extra={
|
|
1734
|
+
"path": str(path),
|
|
1735
|
+
"age_seconds": age_seconds,
|
|
1736
|
+
"ttl": RESTART_SIGNAL_TTL,
|
|
1737
|
+
},
|
|
1738
|
+
)
|
|
1739
|
+
_safe_remove(path)
|
|
1740
|
+
continue
|
|
1741
|
+
except Exception as exc:
|
|
1742
|
+
log.warning("解析重启信号时间戳失败: %s", exc, extra={"path": str(path)})
|
|
1743
|
+
|
|
1744
|
+
if path != RESTART_SIGNAL_PATH:
|
|
1745
|
+
log.info(
|
|
1746
|
+
"从兼容路径读取重启信号",
|
|
1747
|
+
extra={"path": str(path), "primary": str(RESTART_SIGNAL_PATH)},
|
|
1748
|
+
)
|
|
1749
|
+
return raw, path
|
|
1750
|
+
|
|
1751
|
+
return None, None
|
|
1738
1752
|
|
|
1739
1753
|
|
|
1740
1754
|
async def _notify_restart_success(bot: Bot) -> None:
|
|
1741
1755
|
"""在新 master 启动时读取 signal 并通知触发者(改进版:支持超时检测和详细诊断)"""
|
|
1742
1756
|
restart_expected = os.environ.pop("MASTER_RESTART_EXPECTED", None)
|
|
1743
|
-
payload = _read_restart_signal()
|
|
1757
|
+
payload, signal_path = _read_restart_signal()
|
|
1744
1758
|
|
|
1745
1759
|
# 定义重启健康检查阈值(2 分钟)
|
|
1746
1760
|
RESTART_HEALTHY_THRESHOLD = 120 # 秒
|
|
@@ -1754,7 +1768,7 @@ async def _notify_restart_success(bot: Bot) -> None:
|
|
|
1754
1768
|
)
|
|
1755
1769
|
if targets:
|
|
1756
1770
|
# 检查启动日志是否有错误信息
|
|
1757
|
-
error_log_dir =
|
|
1771
|
+
error_log_dir = LOG_ROOT_PATH
|
|
1758
1772
|
error_log_hint = ""
|
|
1759
1773
|
try:
|
|
1760
1774
|
error_logs = sorted(error_log_dir.glob("master_error_*.log"), key=lambda p: p.stat().st_mtime, reverse=True)
|
|
@@ -1775,8 +1789,8 @@ async def _notify_restart_success(bot: Bot) -> None:
|
|
|
1775
1789
|
"4. start.sh 启动失败后被清理",
|
|
1776
1790
|
"",
|
|
1777
1791
|
"建议检查:",
|
|
1778
|
-
f"- 启动日志: {
|
|
1779
|
-
f"- 运行日志: {
|
|
1792
|
+
f"- 启动日志: {LOG_ROOT_PATH / 'start.log'}",
|
|
1793
|
+
f"- 运行日志: {LOG_ROOT_PATH / 'vibe.log'}",
|
|
1780
1794
|
f"- 信号文件: {RESTART_SIGNAL_PATH}",
|
|
1781
1795
|
]
|
|
1782
1796
|
if error_log_hint:
|
|
@@ -1798,7 +1812,11 @@ async def _notify_restart_success(bot: Bot) -> None:
|
|
|
1798
1812
|
chat_id = int(chat_id_raw)
|
|
1799
1813
|
except (TypeError, ValueError):
|
|
1800
1814
|
log.error("重启信号 chat_id 非法: %s", chat_id_raw)
|
|
1801
|
-
|
|
1815
|
+
targets = (signal_path, RESTART_SIGNAL_PATH, *LEGACY_RESTART_SIGNAL_PATHS)
|
|
1816
|
+
for candidate in targets:
|
|
1817
|
+
if candidate is None:
|
|
1818
|
+
continue
|
|
1819
|
+
_safe_remove(candidate)
|
|
1802
1820
|
return
|
|
1803
1821
|
|
|
1804
1822
|
username = payload.get("username")
|
|
@@ -1843,7 +1861,7 @@ async def _notify_restart_success(bot: Bot) -> None:
|
|
|
1843
1861
|
details.append("⚠️ 重启耗时过长,建议检查:")
|
|
1844
1862
|
details.append(" - 网络连接是否正常")
|
|
1845
1863
|
details.append(" - 依赖安装是否卡住")
|
|
1846
|
-
details.append(f" - 启动日志: {
|
|
1864
|
+
details.append(f" - 启动日志: {LOG_ROOT_PATH / 'start.log'}")
|
|
1847
1865
|
else:
|
|
1848
1866
|
message_lines.append("master 已重新上线 ✅")
|
|
1849
1867
|
|
|
@@ -1860,7 +1878,11 @@ async def _notify_restart_success(bot: Bot) -> None:
|
|
|
1860
1878
|
# 重启成功后不再附带项目列表,避免高频重启时产生额外噪音
|
|
1861
1879
|
log.info("重启成功通知已发送", extra={"chat": chat_id, "duration": restart_duration})
|
|
1862
1880
|
finally:
|
|
1863
|
-
|
|
1881
|
+
candidates = (signal_path, RESTART_SIGNAL_PATH, *LEGACY_RESTART_SIGNAL_PATHS)
|
|
1882
|
+
for candidate in candidates:
|
|
1883
|
+
if candidate is None:
|
|
1884
|
+
continue
|
|
1885
|
+
_safe_remove(candidate)
|
|
1864
1886
|
|
|
1865
1887
|
|
|
1866
1888
|
async def _ensure_manager() -> MasterManager:
|
scripts/master_healthcheck.py
CHANGED
|
@@ -25,11 +25,15 @@ from urllib.error import URLError, HTTPError
|
|
|
25
25
|
from urllib.request import Request, urlopen
|
|
26
26
|
|
|
27
27
|
# 导入 master 中的配置与工具,复用项目解析逻辑
|
|
28
|
+
ROOT_DIR = Path(__file__).resolve().parent.parent
|
|
29
|
+
ROOT_DIR_STR = str(ROOT_DIR)
|
|
30
|
+
if ROOT_DIR_STR not in sys.path:
|
|
31
|
+
# 确保可以从仓库根目录导入 master 模块
|
|
32
|
+
sys.path.insert(0, ROOT_DIR_STR)
|
|
33
|
+
|
|
28
34
|
import master # type: ignore
|
|
29
35
|
from project_repository import ProjectRepository
|
|
30
|
-
|
|
31
|
-
ROOT_DIR = Path(__file__).resolve().parent.parent
|
|
32
|
-
DEFAULT_MASTER_LOG = ROOT_DIR / "vibe.log"
|
|
36
|
+
DEFAULT_MASTER_LOG = master.LOG_ROOT_PATH / "vibe.log"
|
|
33
37
|
DEFAULT_TIMEOUT_MASTER = 60.0
|
|
34
38
|
DEFAULT_TIMEOUT_PROBE = 15.0
|
|
35
39
|
PROBE_TEXT = "hello"
|
scripts/start.sh
CHANGED
|
@@ -2,16 +2,21 @@
|
|
|
2
2
|
set -eo pipefail
|
|
3
3
|
|
|
4
4
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
MASTER_CONFIG_ROOT="${MASTER_CONFIG_ROOT:-$HOME/.config/vibego}"
|
|
6
|
+
STATE_DIR="$MASTER_CONFIG_ROOT/state"
|
|
7
|
+
LOG_DIR="$MASTER_CONFIG_ROOT/logs"
|
|
8
|
+
LOCK_FILE="$STATE_DIR/master_restart.lock"
|
|
7
9
|
START_LOG="$LOG_DIR/start.log"
|
|
8
|
-
CODEX_STAMP_FILE="$
|
|
10
|
+
CODEX_STAMP_FILE="$STATE_DIR/npm_codex_install.stamp"
|
|
9
11
|
CODEX_INSTALL_TTL="${CODEX_INSTALL_TTL:-86400}"
|
|
10
12
|
|
|
11
13
|
# 统一重启信号文件路径:使用配置目录而非代码目录
|
|
12
14
|
# 这样 pipx 安装的 master 和源码运行的 master 可以共享同一个信号文件
|
|
13
|
-
|
|
14
|
-
export
|
|
15
|
+
export MASTER_RESTART_SIGNAL_PATH="$STATE_DIR/restart_signal.json"
|
|
16
|
+
export LOG_ROOT="${LOG_ROOT:-$LOG_DIR}"
|
|
17
|
+
if [[ -z "${LOG_FILE:-}" ]]; then
|
|
18
|
+
export LOG_FILE="$LOG_DIR/vibe.log"
|
|
19
|
+
fi
|
|
15
20
|
|
|
16
21
|
log_line() {
|
|
17
22
|
local ts
|
|
@@ -191,7 +196,7 @@ cleanup_old_master() {
|
|
|
191
196
|
local max_wait=10 # 最多等待10秒优雅退出
|
|
192
197
|
local waited=0
|
|
193
198
|
local old_pids=""
|
|
194
|
-
local master_pid_file="$
|
|
199
|
+
local master_pid_file="$STATE_DIR/master.pid"
|
|
195
200
|
|
|
196
201
|
# 方案1:优先从 PID 文件读取
|
|
197
202
|
if [[ -f "$master_pid_file" ]]; then
|
|
@@ -401,7 +406,7 @@ if ! kill -0 "$MASTER_PID" 2>/dev/null; then
|
|
|
401
406
|
exit 1
|
|
402
407
|
fi
|
|
403
408
|
|
|
404
|
-
log_info "master 已后台启动,PID=$MASTER_PID,日志写入
|
|
409
|
+
log_info "master 已后台启动,PID=$MASTER_PID,日志写入 ${LOG_FILE}"
|
|
405
410
|
|
|
406
411
|
# 健康检查:等待 master 上线并验证关键 worker
|
|
407
412
|
log_info "开始执行健康检查..."
|
|
@@ -417,8 +422,8 @@ else
|
|
|
417
422
|
log_error "⚠️ master 健康检查失败,耗时 ${HEALTHCHECK_DURATION}s"
|
|
418
423
|
log_error "建议检查:"
|
|
419
424
|
log_error " - 进程状态: ps aux | grep 'python.*master.py'"
|
|
420
|
-
log_error " - 启动日志: tail -100 $
|
|
421
|
-
log_error " - 运行日志: tail -100 $
|
|
425
|
+
log_error " - 启动日志: tail -100 $LOG_DIR/start.log"
|
|
426
|
+
log_error " - 运行日志: tail -100 $LOG_FILE"
|
|
422
427
|
log_error " - 进程 PID: $MASTER_PID"
|
|
423
428
|
|
|
424
429
|
# 检查进程是否仍在运行
|
scripts/stop_all.sh
CHANGED
|
@@ -2,9 +2,13 @@
|
|
|
2
2
|
set -euo pipefail
|
|
3
3
|
|
|
4
4
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
5
|
-
|
|
5
|
+
MASTER_CONFIG_ROOT="${MASTER_CONFIG_ROOT:-$HOME/.config/vibego}"
|
|
6
|
+
STATE_DIR="$MASTER_CONFIG_ROOT/state"
|
|
6
7
|
LOCK_FILE="$STATE_DIR/master_restart.lock"
|
|
7
8
|
RESTART_SIGNAL="$STATE_DIR/restart_signal.json"
|
|
9
|
+
LEGACY_STATE_DIR="$ROOT_DIR/state"
|
|
10
|
+
LEGACY_LOCK_FILE="$LEGACY_STATE_DIR/master_restart.lock"
|
|
11
|
+
LEGACY_RESTART_SIGNAL="$LEGACY_STATE_DIR/restart_signal.json"
|
|
8
12
|
DEFAULT_TMUX_PREFIX="${TMUX_SESSION_PREFIX:-vibe}"
|
|
9
13
|
STOP_BOT_SCRIPT="$ROOT_DIR/scripts/stop_bot.sh"
|
|
10
14
|
|
|
@@ -138,7 +142,7 @@ stop_tmux_sessions() {
|
|
|
138
142
|
|
|
139
143
|
cleanup_state_files() {
|
|
140
144
|
local removed=0
|
|
141
|
-
for file in "$LOCK_FILE" "$RESTART_SIGNAL"; do
|
|
145
|
+
for file in "$LOCK_FILE" "$RESTART_SIGNAL" "$LEGACY_LOCK_FILE" "$LEGACY_RESTART_SIGNAL"; do
|
|
142
146
|
if [[ -e "$file" ]]; then
|
|
143
147
|
if (( DRY_RUN )); then
|
|
144
148
|
log_info "[dry-run] rm -f $file"
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
bot.py,sha256=TthqY_Rvndzd3pgLH6lvPcsDXQbwkuMfB4W9qt_Li8I,273832
|
|
2
2
|
logging_setup.py,sha256=gvxHi8mUwK3IhXJrsGNTDo-DR6ngkyav1X-tvlBF_IE,4613
|
|
3
|
-
master.py,sha256=
|
|
3
|
+
master.py,sha256=uFRhROoRvd93CTRzS6DdlvxMYok7q1jRWZwe8QrTqIY,113997
|
|
4
4
|
project_repository.py,sha256=UcthtSGOJK0cTE5bQCneo3xkomRG-kyc1N1QVqxeHIs,17577
|
|
5
5
|
scripts/__init__.py,sha256=LVrXUkvWKoc6Sb47X5G0gbIxu5aJ2ARW-qJ14vwi5vM,65
|
|
6
6
|
scripts/bump_version.sh,sha256=a4uB8V8Y5LPsoqTCdzQKsEE8HhwpBmqRaQInG52LDig,4089
|
|
7
7
|
scripts/log_writer.py,sha256=8euoMlRo7cbtHApbcEoJnwzLABxti-ovJWFLRN1oDQw,3843
|
|
8
|
-
scripts/master_healthcheck.py,sha256
|
|
8
|
+
scripts/master_healthcheck.py,sha256=kvE6owdqyLmfQ-UYY_jglg86xFzOc87sINxBe5_qWzk,8489
|
|
9
9
|
scripts/publish.sh,sha256=ehLfMedcXuGKJ87jpZy3kuiFszG9Cpavp3zXPfR4h-g,3511
|
|
10
10
|
scripts/requirements.txt,sha256=ukJbFLJyzqnQYMz6j07O-IOrG87IwXg0oikmn1nfJ9M,91
|
|
11
11
|
scripts/run_bot.sh,sha256=rN4K1nz041XBaUJmnBBKHS2cHmQf11vPNX8wf1hbVR4,4596
|
|
12
|
-
scripts/start.sh,sha256=
|
|
12
|
+
scripts/start.sh,sha256=1jmO-UVsLskIMdh_2qn130PZ80bVl3CiFpP6XKaXiJk,13695
|
|
13
13
|
scripts/start_tmux_codex.sh,sha256=xyLv29p924q-ysxvZYAP3T6VrqLPBPMBWo9QP7cuL50,4438
|
|
14
|
-
scripts/stop_all.sh,sha256=
|
|
14
|
+
scripts/stop_all.sh,sha256=VbNX4h8g1RcnGmLyutPcSySTHb84eIMbo3Ve9Vh-CDg,4360
|
|
15
15
|
scripts/stop_bot.sh,sha256=ot6Sm0IYoXuRNslUVEflQmJKu5Agm-5xIUXXudJWyTM,5588
|
|
16
16
|
scripts/test_deps_check.sh,sha256=AeSTucbNuNdOPSGvqVp0m31TVFDb0DmU8gSKg-Y5z2I,1696
|
|
17
17
|
scripts/.venv/lib/python3.14/site-packages/pip/__init__.py,sha256=_lgs5Mfp0t7AGtI7sTVwxKWquz_vahWWH9kKO1cJusA,353
|
|
@@ -426,14 +426,14 @@ tasks/constants.py,sha256=tS1kZxBIUm3JJUMHm25XI-KHNUZl5NhbbuzjzL_rF-c,299
|
|
|
426
426
|
tasks/fsm.py,sha256=rKXXLEieQQU4r2z_CZUvn1_70FXiZXBBugF40gpe_tQ,1476
|
|
427
427
|
tasks/models.py,sha256=N_qqRBo9xMSV0vbn4k6bLBXT8C_dp_oTFUxvdx16ZQM,2459
|
|
428
428
|
tasks/service.py,sha256=w_S_aWiVqRXzXEpimLDsuCCCX2lB5uDkff9aKThBw9c,41916
|
|
429
|
-
vibego_cli/__init__.py,sha256=
|
|
429
|
+
vibego_cli/__init__.py,sha256=kV9sTUnKB8boKxSGFUxB66yqQiYg2LvSz9Yu-vLd8_0,311
|
|
430
430
|
vibego_cli/__main__.py,sha256=qqTrYmRRLe4361fMzbI3-CqpZ7AhTofIHmfp4ykrrBY,158
|
|
431
431
|
vibego_cli/config.py,sha256=VxkPJMq01tA3h3cOkH-z_tiP7pMgfSGGicRvUnCWkhI,3054
|
|
432
432
|
vibego_cli/deps.py,sha256=1nRXI7Dd-S1hYE8DligzK5fIluQWETRUj4_OKL0DikQ,1419
|
|
433
433
|
vibego_cli/main.py,sha256=X__NXwZnIDIFbdKSTbNyZgZHKcPlN0DQz9sqTI1aQ9E,12158
|
|
434
434
|
vibego_cli/data/worker_requirements.txt,sha256=QSt30DSSSHtfucTFPpc7twk9kLS5rVLNTcvDiagxrZg,62
|
|
435
|
-
vibego-0.2.
|
|
436
|
-
vibego-0.2.
|
|
437
|
-
vibego-0.2.
|
|
438
|
-
vibego-0.2.
|
|
439
|
-
vibego-0.2.
|
|
435
|
+
vibego-0.2.43.dist-info/METADATA,sha256=dl3SxrEq4PXFbvL7S9NfXaKYvGyA4XZQr89290NTaV8,10519
|
|
436
|
+
vibego-0.2.43.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
437
|
+
vibego-0.2.43.dist-info/entry_points.txt,sha256=Lsy_zm-dlyxt8-9DL9blBReIwU2k22c8-kifr46ND1M,48
|
|
438
|
+
vibego-0.2.43.dist-info/top_level.txt,sha256=R56CT3nW5H5v3ce0l3QDN4-C4qxTrNWzRTwrxnkDX4U,69
|
|
439
|
+
vibego-0.2.43.dist-info/RECORD,,
|
vibego_cli/__init__.py
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|