chore: 归档fix-horse-racing-issues提案

This commit is contained in:
2026-05-01 23:15:08 +08:00
parent a2b7e1fc11
commit 9566920866
8 changed files with 326 additions and 0 deletions

View File

@@ -0,0 +1,106 @@
## Technical Design
### 1. SQLite → aiosqlite
\\\python
# room_store.py
import aiosqlite
class RoomStore:
async def _get_conn(self) -> aiosqlite.Connection:
db_path = Path(self.config.DB_PATH)
db_path.parent.mkdir(parents=True, exist_ok=True)
conn = await aiosqlite.connect(str(db_path))
conn.row_factory = aiosqlite.Row
await conn.execute('''CREATE TABLE IF NOT EXISTS race_history (...)''')
await conn.commit()
return conn
async def get_last_horse_name(self, user_id: str) -> Optional[str]:
conn = await self._get_conn()
try:
cursor = await conn.execute("SELECT horse_name FROM ...", (user_id,))
row = await cursor.fetchone()
return row[0] if row else None
finally:
await conn.close()
\\\
> 每次操作独立连接和关闭保持与原逻辑一致,仅将同步调用替换为 async。
### 2. 积分重试加延时 + 区分失败原因
\\\python
# points_service.py
async def spend_bet_points(self, user_id: str, amount: int, reason: str = "赛马下注"):
success, balance = await points_api.spend_points(user_id, amount, "horse_race", reason)
if success:
return True, balance
# 余额不足不再重试
if balance < amount:
return False, balance
# 网络/其他失败短暂等待后重试一次
await asyncio.sleep(1.0)
success, balance = await points_api.spend_points(user_id, amount, "horse_race", reason)
return success, balance
\\\
### 3. 消息发送加日志
\\\python
# commands.py
import logging
logger = logging("group_horse_racing")
async def _send_to_scope(bot: Bot, scope: str, message: ...):
try:
if scope.startswith("group_"):
await bot.send_group_msg(...)
elif scope.startswith("test_"):
await bot.send_private_msg(...)
except Exception:
logger.warning(f"发送消息到 {scope} 失败", exc_info=True)
\\\
### 4. 赔率快照(结算时锁内固定)
在比赛结束结算时将赔率在 Room Lock 内计算后传入结算函数保证赔率与下注分布一致
\\\python
# 在 start_race 的 lock 内计算赔率快照
odds_snapshot = {}
for horse_name, horse in room.horses.items():
odds_snapshot[horse_name] = room.calculate_odds(horse_name) # 锁内计算
# 传入结算函数使用快照赔率
await _settle_race(bot, event, room, config, odds_snapshot)
\\\
### 5. 补存积分变化
\\\python
# room_store.py - save_race_result
await conn.execute(
"INSERT INTO race_history (...point_changes, point_change_summaries) VALUES (..., ?, ?)",
(...,
json.dumps(result.point_changes),
json.dumps(result.point_change_summaries))
)
\\\
需在 CREATE TABLE 中新增两个 TEXT 字段使用 \IF NOT EXISTS\ 保证兼容
### 6. 测试数据隔离
\\\python
# test_commands.py
from .commands import get_scope, check_access, race_engine, _rooms as prod_rooms
from .room_store import RoomStore as _RealRoomStore
# 测试命令用独立 store
_test_store = _RealRoomStore(config) # 或用内存 store
\\\
> 不再共享生产 room_store 实例,测试操作独立数据。
### 7. 马名去重统一
dict key 统一用 normalized namecasefold或在注册时统一用原始名但比较用 casefold