4b83452294
首跑5yr 673/5493后baostock连接死、定时重连没恢复、登录卡死=被限流。修四个硬伤: - 重登on-error: except分支强制bs.logout+login建新socket再retry(原只sleep重试同死socket) - 登录超时: SIGALRM给bs.login套30s闹钟,防永久挂起 - 断路器: 连续30只failed→save_progress+break+exit 2,不再假完成空跑2000票 - marker-resume: load_progress扫.baostock marker文件(非done JSON),failed无marker永远重试 - watcher: 每30min探测baostock,可登就续跑,冷却就等,exit 0则退出 9/9单测绿(Mac venv311 mock baostock)。
69 lines
2.3 KiB
Python
69 lines
2.3 KiB
Python
"""5yr 15min 回填冷却后自动续跑 watcher。
|
||
|
||
baostock 被限流/冷却时登录会卡死或失败。本 watcher 每 30min 探测一次 baostock,
|
||
可登就启动 backfill_15min_baostock(marker-based resume 自动续跑缺口),断路器触发
|
||
或登录失败就继续等。backfill 成功(exit 0,全部缺口填完)则退出。
|
||
|
||
detached 启动:
|
||
nohup ./venv311/bin/python3 scripts/data_platform/resume_5yr_watcher.py \
|
||
> /Users/chufeng/data_cache/stock/logs/daily_update/resume_watcher.log 2>&1 &!
|
||
"""
|
||
import os
|
||
import subprocess
|
||
import time
|
||
|
||
ROOT = "/Users/chufeng/.openclaw/sanguo_projects/sanguo_vnpy_v2"
|
||
PY = os.path.join(ROOT, "venv311/bin/python3")
|
||
SCRIPT = os.path.join(ROOT, "scripts/data_platform/backfill_15min_baostock.py")
|
||
PROBE_INTERVAL = 1800 # 30min
|
||
|
||
# 探测脚本:SIGALRM 给 bs.login() 套 15s 闹钟,避免卡死
|
||
_PROBE = r'''
|
||
import signal
|
||
def _h(*a): raise TimeoutError()
|
||
signal.signal(signal.SIGALRM, _h)
|
||
signal.alarm(15)
|
||
try:
|
||
import baostock as bs
|
||
lg = bs.login()
|
||
ok = lg.error_code == "0"
|
||
try: bs.logout()
|
||
except Exception: pass
|
||
print("LOGIN_OK" if ok else "LOGIN_FAIL")
|
||
except Exception as e:
|
||
print("LOGIN_ERR", type(e).__name__, e)
|
||
finally:
|
||
signal.alarm(0)
|
||
'''
|
||
|
||
|
||
def baostock_up() -> bool:
|
||
try:
|
||
r = subprocess.run([PY, "-c", _PROBE], capture_output=True, text=True, timeout=30)
|
||
return "LOGIN_OK" in r.stdout
|
||
except Exception:
|
||
return False
|
||
|
||
|
||
def main() -> None:
|
||
round_ = 0
|
||
while True:
|
||
round_ += 1
|
||
if baostock_up():
|
||
print(f"[round {round_}] baostock 可登,启动回填(marker-resume 续跑缺口)", flush=True)
|
||
env = dict(os.environ)
|
||
env["STOCK_ROOT"] = "/Users/chufeng/data_cache/stock"
|
||
env["BS_START_DATE"] = "20210101"
|
||
rc = subprocess.call([PY, SCRIPT], env=env, cwd=ROOT)
|
||
if rc == 0:
|
||
print(f"[round {round_}] 回填完成(exit 0),退出 watcher", flush=True)
|
||
return
|
||
print(f"[round {round_}] 回填 exit={rc}(断路器/失败),等 {PROBE_INTERVAL}s 再试", flush=True)
|
||
else:
|
||
print(f"[round {round_}] baostock 不可登(冷却中),等 {PROBE_INTERVAL}s", flush=True)
|
||
time.sleep(PROBE_INTERVAL)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|