Files
Hermes-Skills/okx-auto-position/references/tg-forwarder-troubleshoot-2026-09-22-to-24.md
T

90 lines
4.0 KiB
Markdown

# TG Forwarder 排查+修复: 硬编码黑名单误杀 + chat_id 提取 bug + 频道切换 (2026-09-22 ~ 2026-09-24)
## 症状
用户报"监听频道要更新 / 现在交易信号都没转发了吗" → 排查发现 forwarder 一直在跑, 但日志显示:
```
[用户] 消息命中硬编码黑名单, 跳过转发
最终决定: 不转发
或
Got difference for channel 2651333064 updates (但 0 处理规则/消息内容日志)
```
## 根因 1: 硬编码黑名单误杀 (2026-09-22)
`/app/handlers/user_handler.py` 的 `HARD_BLACKLIST_PATTERNS` 含
`r'(?i)usdt|cny|套现'` 和裸 `带单|指导|喊单|牛牛老师`、`\bVIP\b|\b老师\b`。
**所有信号都带 USDT** (【币种】:BTCUSDT 永续) → 每条都命中 → 信号时有时无。
修复 (收窄正则):
```python
# 修复前 (误杀)
r'(?i)usdt|cny|套现',
r'(?i)带单|指导|喊单|牛牛老师',
r'(?i)\bVIP\b|\b老师\b',
# 修复后
r'(?i)(usdt|cny)(?!永续|usdt).{0,4}套现|套现',
r'(?i)牛牛老师|喊单指导',
r'(?i)\bVIP群\b|付费指导',
```
改完必须 `docker restart telegram-forwarder`。
## 根因 2: chat_id 提取 bug (2026-09-24)
切换 source 到新频道 @shipan_jiankong 后, forwarder 收到 `Got difference for channel 2651333064 updates` (每15分钟轮询一次), 但**完全没"消息内容/处理规则"日志**。
`/app/message_listener.py` line 75-76:
```python
chat = await event.get_chat()
chat_id = abs(chat.id) # 错! 剥掉了 -100 前缀
```
实际 telethon:
- `event.chat.id` = 正数 `2651333064` (Channel 对象剥了 -100)
- `event.chat_id` = 完整 `-1002651333064` ← 正确
DB 存 `Chat.telegram_chat_id == '-1002651333064'` 字符串, `str(2651333064)` 永远匹配不上 → Chat 查询 None → 早 return → 无日志。
后续 `int(f"100{chat_id}")` 二次覆盖更错 (应是 `-100{...}`), 但只在 `state_manager.check_state()` 为真时触发。
修复:
```python
chat = await event.get_chat()
chat_id = event.chat_id # 用完整 -100xxxxxxxxxx
```
同时 Chat 查询加防御, 兼容两种格式 (防御性, 防止 chat_id 来源不一致时再次错):
```python
_chat_id_str = str(chat_id)
if abs(chat_id) > 1e10 and not _chat_id_str.startswith('-100'):
_alt_id_str = f'-100{abs(chat_id) - 1e12}' if abs(chat_id) > 1e12 else f'-100{_chat_id_str}'
else:
_alt_id_str = f'100{_chat_id_str.lstrip("-")}'
source_chat = session.query(Chat).filter(
Chat.telegram_chat_id.in_([_chat_id_str, _alt_id_str, f'-100{_chat_id_str.lstrip("100")}'])
).first()
```
修改后必须 `docker restart telegram-forwarder`。
## 双频道区分 (易混, 别再装错)
| 频道 | chat_id | 标题 | 当前状态 |
|---|---|---|---|
| **@shipan_jiankong** | -1002651333064 | 币圈实盘监控 \| 熬鹰 风寻 | ✅ **当前 source** (chats.id=4) |
| @jiankongshipan | 3805472665 | 实盘监控 | ❌ 已停用, 记录保留 (chats.id=1) |
频道切换 SQL:
```sql
INSERT INTO chats (telegram_chat_id, name, current_add_id) VALUES ('-1002651333064', '币圈实盘监控 熬鹰 风寻', NULL);
UPDATE forward_rules SET source_chat_id = (SELECT id FROM chats WHERE telegram_chat_id='-1002651333064') WHERE id=1;
```
## 双白名单 AND 校验 (v4.5.4, 未动)
消息必须同时含交易员关键词 (麻吉/魏神/熬鹰/风寻/狙击手/百发百胜) + 信号类型 (开仓/平仓/加仓/减仓) 才转发。
## 排查手法 (套路)
- 规则库: 容器内 `python3 -c "import sqlite3; ..."` 读 `/app/db/forward.db` (chats/forward_rules/keywords 表)
- session 被主进程锁 → `cp /app/sessions/user.session /tmp/xx.session` 再连
- 容器内连 TG 必带 `proxy=('socks5','127.0.0.1',7891)`, `request_retries=1` + timeout 防挂
- 容器内无 sqlite3 CLI, 用 python sqlite3 模块
- 验证消息实体存在: `async for m in c.iter_messages(username, limit=10)`
- 验证 chat.id vs chat_id 区别: `print(event.chat.id, event.chat_id)`
- 区分 telethon.channel.get_difference (轮询 update) vs message.NewMessage (新消息事件)
- 复现信号让用户从实际频道发一条, 看 docker logs --since 1m | grep 处理规则 是否命中