fix(test): 修复完全模拟赛马测试的并发与超时问题
- 将锁获取改为带超时的等待,避免因锁占用导致测试卡死 - 增加模拟任务的超时控制,防止无限等待 - 添加异常捕获与详细错误信息输出,便于问题定位 - 确保在测试异常或超时后正确清理资源
This commit is contained in:
@@ -8,6 +8,7 @@ from .models import Horse, HorseState, RoomState, Bet, RaceResult
|
|||||||
import asyncio
|
import asyncio
|
||||||
import random
|
import random
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
import traceback
|
||||||
|
|
||||||
from . import commands as commands_mod
|
from . import commands as commands_mod
|
||||||
|
|
||||||
@@ -205,10 +206,17 @@ async def handle_test_simulate_race(bot: Bot, event: Event):
|
|||||||
|
|
||||||
scope = get_scope(event)
|
scope = get_scope(event)
|
||||||
lock = room_store.get_lock(scope)
|
lock = room_store.get_lock(scope)
|
||||||
|
try:
|
||||||
|
await asyncio.wait_for(lock.acquire(), timeout=3)
|
||||||
|
except TimeoutError:
|
||||||
|
await test_simulate_race_cmd.finish("完全模拟失败:房间锁被占用(可能有卡住的赛马/测试任务),请稍后重试或先重启 Bot")
|
||||||
|
return
|
||||||
|
|
||||||
async with lock:
|
try:
|
||||||
race_engine.stop_race(scope)
|
race_engine.stop_race(scope)
|
||||||
room_store.delete_room(scope)
|
room_store.delete_room(scope)
|
||||||
|
finally:
|
||||||
|
lock.release()
|
||||||
|
|
||||||
original_room_store = commands_mod.room_store
|
original_room_store = commands_mod.room_store
|
||||||
original_points_service = commands_mod.points_service
|
original_points_service = commands_mod.points_service
|
||||||
@@ -220,6 +228,9 @@ async def handle_test_simulate_race(bot: Bot, event: Event):
|
|||||||
fake_message_service = _NoopMessageService()
|
fake_message_service = _NoopMessageService()
|
||||||
fake_bot = _FakeBot()
|
fake_bot = _FakeBot()
|
||||||
|
|
||||||
|
start_task: asyncio.Task | None = None
|
||||||
|
room = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
commands_mod.room_store = fake_room_store
|
commands_mod.room_store = fake_room_store
|
||||||
commands_mod.points_service = fake_points_service
|
commands_mod.points_service = fake_points_service
|
||||||
@@ -243,7 +254,7 @@ async def handle_test_simulate_race(bot: Bot, event: Event):
|
|||||||
|
|
||||||
start_task = asyncio.create_task(commands_mod.run_race_with_settlement(fake_bot, room, scope))
|
start_task = asyncio.create_task(commands_mod.run_race_with_settlement(fake_bot, room, scope))
|
||||||
commands_mod.race_engine.register_task(scope, start_task)
|
commands_mod.race_engine.register_task(scope, start_task)
|
||||||
await start_task
|
await asyncio.wait_for(start_task, timeout=15)
|
||||||
|
|
||||||
messages = [m.get("message", "") for m in fake_bot.messages]
|
messages = [m.get("message", "") for m in fake_bot.messages]
|
||||||
if not messages:
|
if not messages:
|
||||||
@@ -295,7 +306,15 @@ async def handle_test_simulate_race(bot: Bot, event: Event):
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
ticks = room.tick_count if room else 0
|
||||||
|
await test_simulate_race_cmd.finish(f"完全模拟失败:超时未完成(当前回合:{ticks})")
|
||||||
|
except Exception as e:
|
||||||
|
tail = "\n".join(traceback.format_exc().splitlines()[-8:])
|
||||||
|
await test_simulate_race_cmd.finish(f"完全模拟异常:{type(e).__name__}: {e}\n{tail}")
|
||||||
finally:
|
finally:
|
||||||
|
if start_task and not start_task.done():
|
||||||
|
start_task.cancel()
|
||||||
commands_mod.room_store = original_room_store
|
commands_mod.room_store = original_room_store
|
||||||
commands_mod.points_service = original_points_service
|
commands_mod.points_service = original_points_service
|
||||||
commands_mod.message_service = original_message_service
|
commands_mod.message_service = original_message_service
|
||||||
|
|||||||
Reference in New Issue
Block a user