处理联调

This commit is contained in:
zlt 2026-07-29 12:15:28 +08:00
parent 5505da5e15
commit 01b3efa684
3 changed files with 74 additions and 9 deletions

View File

@ -471,8 +471,27 @@ class WsRunner:
self._stat["last_reject"] = (
f"{code or '(无 code)'} · {str(pl.get('reason') or '(无 reason)')[:80]}"
f" · 针对 {iid or '(消息未带 instruction_id)'}")
# reject 按协议是**委托级**响应, 必然带 instruction_id。不带的话它拒的就不是
# 委托, 而是我们发的某条协议消息 (hello/ping/ack_seq) —— 这是通道故障, 不是
# 交易结果, 不能拿去改委托状态 (iid 为空时 update_order 是空转, 更糟的是它把
# 故障伪装成了"没事发生")。这里分开计数并原样打出整条 payload: 对端的 reject
# 可能带我们没读的字段, 猜不如看。
if not iid:
self._stat["proto_rejects"] = self._stat.get("proto_rejects", 0) + 1
n = self._stat["proto_rejects"]
if n <= 3 or n % 50 == 0:
logger.error("[协议级 reject #%s] 对端拒绝了我们发的一条协议消息 "
"(非委托, 无 instruction_id)。整条 payload: %s",
n, json.dumps(pl, ensure_ascii=False)[:500])
if n == 10:
logger.error("协议级 reject 已达 10 条且仍在增长: 很可能是"
"「我们 ack → 对端拒 → 拒绝本身带 seq → 我们又要 ack」"
"的自激循环, 通道看着 ONLINE 其实什么也没在做。"
"请拿上面的 payload 与 QMT 侧对齐消息格式")
else:
await _db(qmt_repo.update_order, iid, status=qmt_repo.OS_REJECTED,
reject_code=code[:32], reject_reason=str(pl.get("reason") or "")[:300],
reject_code=code[:32],
reject_reason=str(pl.get("reason") or "")[:300],
final_at=datetime.now())
# 设计 §13: 指令下发失败不自动重发。可重试码也只是记下来,
# 由 executor 下一跳按最新行情重新决定 —— 换价重发的判断权在择时模块。

40
scripts/deploy.sh Normal file
View File

@ -0,0 +1,40 @@
#!/usr/bin/env bash
# tradingSystem (PMS) 一键部署
# ---------------------------------------------------------------------------
# 为什么需要它: 源码是**打进镜像**的 (docker-compose.yml 只挂了 ./logs), 所以
# `docker compose restart` 只是把老容器停了再起, 跑的还是旧镜像里的旧代码 ——
# 改完代码 restart 一下看不到变化, 而且**一点报错都没有**, 排查时极其误导。
# 代码改动要生效必须 build + force-recreate, 这个脚本就是干这个的。
#
# 用法:
# ./scripts/deploy.sh 拉代码 → 重建镜像 → 重建服务 → 报状态
# ./scripts/deploy.sh --no-pull 跳过 git pull (本地已改好, 不想拉远端)
# PROFILES="--profile ws" ./scripts/deploy.sh 只跑页面 + ws (默认 sched+ws)
# ---------------------------------------------------------------------------
set -euo pipefail
cd "$(dirname "$0")/.."
PROFILES="${PROFILES:---profile sched --profile ws}"
DC=(docker compose $PROFILES)
if [[ "${1:-}" != "--no-pull" ]]; then
echo "==> git pull"
git pull --ff-only
fi
echo "==> 重建镜像"
"${DC[@]}" build
echo "==> 重建容器 (force-recreate: 让新镜像真正生效)"
"${DC[@]}" up -d --force-recreate
echo
"${DC[@]}" ps
echo
echo "==> 建表/补表 (幂等)"
docker compose run --rm --no-deps pms-web python scripts/init_db.py --yes || {
echo "建表失败 —— 上面有原因, 服务已经起来了, 修完重跑本脚本即可"; exit 1; }
echo
echo "完成。ws 通道状态:"
echo " docker compose run --rm --no-deps pms-web python scripts/ws_smoke.py status"

View File

@ -96,7 +96,13 @@ def cmd_status(args):
f"持续增长则说明序号语义对不上")
if int(s.get("reconnects") or 0) >= 5:
bad.append(f"重连 {s['reconnects']} 次: 连接不稳, 见上面「最后断开原因」")
if int(s.get("rejects") or 0) and not qmt_repo.list_orders(limit=1):
if int(s.get("proto_rejects") or 0):
bad.append(f"协议级 reject {s['proto_rejects']} 条 (不带 instruction_id, 拒的不是委托"
f"而是我们发的协议消息)。若 rx≈tx 且两者同步增长, 基本可以断定是"
f"「我们 ack → 对端拒 → 拒绝本身带 seq → 我们又要 ack」的自激循环: "
f"通道显示 ONLINE, 实际什么也没在做。整条 payload 见 "
f"docker compose logs pms-ws | grep 协议级")
elif int(s.get("rejects") or 0) and not qmt_repo.list_orders(limit=1):
bad.append(f"出口表一张委托都没有, 却收到 {s['rejects']} 条 reject —— 对端在拒绝我们"
f"的非委托消息 (hello/ping/ack?), 见上面「最后一条拒绝」")
if ch.get("resync_required"):