Files
MoFin/archive/hermes-dead-tools-20260820/verify_deployment.py
T
xxm c68f987653 chore(cleansweep): 代码大扫除——归档hermes 111个死工具+4个废弃scanner,收敛MoFin/scripts重复副本,删除根旧版mo_models
- archive/hermes-dead-tools-20260820/: hermes独有不在cron不被import的111个一次性排查/测试工具
- archive/hermes-dead-tools-20260820/: 4个废弃scanner(btd1_v3/market_scanner/market_thermometer已废弃/s2v2)
- archive/legacy-cleanup-20260820/: MoFin根2旧版(mo_models/technical_analysis)+/home/hmo/scripts无引用旧项目+MoFin/scripts重复prepare_report_data
- 删除MoFin根mo_models.py(根旧版,deploy/profile-scripts权威保留)
- 保留: mofin_db.py/mo_data.py硬链接(server.py多层sys.path需各目录访问同一inode,非冗余)
- fix_gateway.py保留(Gateway看门狗fix_gateway_port.py的活跃依赖,勿误删)
- 验证: cron所有脚本引用无缺失, key模块import正常
- hermes独有从116收敛到5核心(alert_logger/market_screener/prepare_report_data/self_todo_executor_v2/xmpp_zhiwei_bot)
2026-08-20 10:36:25 +08:00

120 lines
5.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import json, os, subprocess, hashlib
from datetime import datetime
now = datetime.now()
ok_count = 0
fail_items = []
def check(name, ok, detail=''):
global ok_count
icon = '✅' if ok else '❌'
print(f'{icon} {name}: {detail}')
if ok:
ok_count += 1
else:
fail_items.append(name)
def md5(p):
try:
return hashlib.md5(open(p, 'rb').read()).hexdigest()[:10]
except Exception:
return 'ERR'
print('=== 1. 新脚本文件部署(deploy + profile scripts 硬链接一致)===')
NEW_SCRIPTS = ['functional_health_check.py', 'self_repair.py', 'meta_watchdog.py',
'system_hygiene_audit.py', 'sync_profile_scripts.sh', 'mofin_health.py']
for f in NEW_SCRIPTS:
dp = f'/home/hmo/MoFin/deploy/profile-scripts/{f}'
pp = f'/home/hmo/.hermes/profiles/position-analyst/scripts/{f}'
d_ok = os.path.exists(dp)
p_ok = os.path.exists(pp)
same = d_ok and p_ok and md5(dp) == md5(pp)
check(f, same, f'deploy={d_ok} profile={p_ok} 内容一致={same}')
print()
print('=== 2. cron 注册(L1/L2/L3/L4 jobs===')
d = json.load(open('/home/hmo/.hermes/profiles/position-analyst/cron/jobs.json'))
jobs = d if isinstance(d, list) else d.get('jobs', [])
expect = {
'functional_health_check.py': 'L1功能健康(15min)',
'self_repair.py': 'L3修复循环(30min)',
'meta_watchdog.py': 'L4元监控(每小时)',
'system_hygiene_audit.py': 'L2卫生(每日)',
}
for script, label in expect.items():
j = next((x for x in jobs if x.get('script') == script), None)
if not j:
check(label, False, '未注册')
else:
sched = j.get('schedule_display') or str(j.get('schedule'))
en = j.get('enabled', True)
check(label, bool(j and en), f'registered sched={sched} enabled={en}')
# 退休的 job 不在
for dead in ['Cron监护-高频', '全局cron健康监控-每10分']:
j = next((x for x in jobs if x.get('name') == dead), None)
check(f'退休job[{dead}]已删除', j is None, '已删除' if j is None else '仍存在!')
print()
print('=== 3. 输出物生成 ===')
for name, path, max_h in [
# L1 和 mofin_health 都是交易时段运行(9-16,20-22 工作日),过夜间隔约13h,
# 阈值 16h 消除夜间/凌晨部署时的假警报;真挂掉(交易日白天不更新)仍会抓到
('functional_health.json', '/home/hmo/MoFin/gateway/logs/functional_health.json', 16),
('hygiene_report.json', '/home/hmo/MoFin/gateway/logs/hygiene_report.json', 26),
('meta_watchdog.json', '/home/hmo/MoFin/gateway/logs/meta_watchdog.json', 2),
('mofin_health.json', '/home/hmo/web-dashboard/static/mofin_health.json', 16),
]:
if not os.path.exists(path):
check(name, False, '不存在')
else:
age_h = (now.timestamp() - os.path.getmtime(path)) / 3600
check(name, age_h < max_h, f'{age_h:.1f}h前生成(阈值{max_h}h')
print()
print('=== 4. mofin_health.json 含 self_check 区块 ===')
try:
mh = json.load(open('/home/hmo/web-dashboard/static/mofin_health.json'))
sc = mh.get('self_check', {})
check('self_check.functional', bool(sc.get('functional')), str(bool(sc.get('functional'))))
check('self_check.meta_watchdog', bool(sc.get('meta_watchdog')), str(bool(sc.get('meta_watchdog'))))
check('self_check.hygiene', bool(sc.get('hygiene')), str(bool(sc.get('hygiene'))))
except Exception as e:
check('mofin_health.json', False, str(e))
print()
print('=== 5. Dashboard 页面含自检体系 Tab ===')
html = open('/home/hmo/web-dashboard/static/mofin_health.html', encoding='utf-8').read()
check('🩺自检体系 tab', '自检体系' in html and 'panel4' in html, '')
r = subprocess.run(['curl', '-s', '-o', '/dev/null', '-w', '%{http_code}',
'http://127.0.0.1:8899/mofin_health.html'], capture_output=True, text=True, timeout=10)
check('dashboard 页面 200', r.stdout.strip() == '200', f'HTTP {r.stdout.strip()}')
print()
print('=== 6. systemd 超时配置 ===')
r1 = subprocess.run(['sudo', '-n', 'systemctl', 'show', 'hermes-gateway-zhiwei', '-p', 'Environment'],
capture_output=True, text=True, timeout=10)
check('zhiwei HERMES_CRON_SCRIPT_TIMEOUT=600', 'HERMES_CRON_SCRIPT_TIMEOUT=600' in r1.stdout, '')
r2 = subprocess.run(['systemctl', '--user', 'show', 'hermes-gateway', '-p', 'Environment'],
capture_output=True, text=True, timeout=10)
check('default HERMES_CRON_SCRIPT_TIMEOUT=600', 'HERMES_CRON_SCRIPT_TIMEOUT=600' in r2.stdout, '')
print()
print('=== 7. 小果残留 ===')
r = subprocess.run(['ps', 'aux'], capture_output=True, text=True, timeout=10)
xg = [l for l in r.stdout.splitlines() if 'xiaoguo' in l.lower() and 'grep' not in l]
check('小果进程清零', len(xg) == 0, f'{len(xg)}个残留' if xg else '无')
r = subprocess.run(['ss', '-tlnp'], capture_output=True, text=True, timeout=10)
check('8645 已关闭', '8645' not in r.stdout, '')
print()
print('=== 8. 服务全景 ===')
r = subprocess.run(['ss', '-tlnp'], capture_output=True, text=True, timeout=10)
for port, label in [('8642', 'default gw'), ('8643', 'zhiwei gw'), ('8646', 'mohe gw'),
('8899', 'dashboard'), ('5222', 'ejabberd'), ('5805', 'xmpp桥')]:
check(f'{label}:{port}', f':{port}' in r.stdout, '')
print()
print(f'=== 汇总: {ok_count} 项通过, {len(fail_items)} 项失败 ===')
if fail_items:
print('失败项:', fail_items)