Conversation
确保抽奖结果中的学生ID能够正确从候选数据中提取并传递到奖品信息中 同时修正抽奖结果显示时学生ID的获取逻辑
当无法附加到共享内存时,增加服务器状态检测和资源清理逻辑 修复本地服务器启动失败时未清理残留socket的问题
在POSIX系统上,QSharedMemory在进程崩溃后不会自动清理残留的共享内存段 添加_cleanup_stale_shared_memory函数来检测并清理这些残留资源
There was a problem hiding this comment.
Pull request overview
该 PR 主要修复抽奖动画阶段的“学号显示错误”(Fixes #211),并增强单实例检测在异常退出后重启时的自恢复能力,避免共享内存/本地 socket 残留导致无法启动。
Changes:
- 抽奖动画帧数据中增加并传递
student_id,在动画展示/通知 IPC 中使用学生 ID 替代奖品 ID。 - 单实例检测增加“本地服务器存活探测 + 残留资源清理 + 失败后重建共享内存”的恢复流程,并在本地服务器 listen 失败时清理 socket 后重试。
- 删除
requirements-windows.txt与requirements-linux.txt(平台 requirements 文件)。
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| app/common/lottery/lottery_manager.py | 动画随机帧携带并使用学生 ID,修复关联学生名单时动画学号越界问题 |
| app/core/single_instance.py | 增加存活检测与残留清理逻辑,改善异常退出后的重启体验 |
| requirements-windows.txt | 删除 Windows 平台 requirements 文件 |
| requirements-linux.txt | 删除 Linux 平台 requirements 文件 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| selected_prizes = [ | ||
| (p.get("student_id", 0) or 0, p["name"], p.get("exist", True)) | ||
| for p in prizes | ||
| ] |
There was a problem hiding this comment.
draw_random() now builds selected_prizes using p.get("student_id", 0) for the tuple's num. When get_random_items() returns prizes without a student_id (e.g., student-assignment disabled, or candidates is empty and it returns selected_prizes directly), this will force the displayed number to 0/00 for all animation frames and changes prior behavior (previously used p["id"]). Consider falling back to the prize id when student_id is missing/0 (or using None to suppress the number), so non-assignment / empty-candidate cases continue to display correctly while still using real student ids when available.
| selected_prizes = [ | |
| (p.get("student_id", 0) or 0, p["name"], p.get("exist", True)) | |
| for p in prizes | |
| ] | |
| selected_prizes = [] | |
| for p in prizes: | |
| try: | |
| display_num = int(p.get("student_id", 0) or 0) | |
| except Exception: | |
| display_num = 0 | |
| if not display_num: | |
| try: | |
| display_num = int(p.get("id", 0) or 0) | |
| except Exception: | |
| display_num = 0 | |
| selected_prizes.append( | |
| (display_num, p["name"], p.get("exist", True)) | |
| ) |
| def _check_server_alive() -> bool: | ||
| """检查本地服务器是否有响应 | ||
|
|
||
| Returns: | ||
| bool: 服务器是否有响应 | ||
| """ | ||
| local_socket = QLocalSocket() | ||
| local_socket.connectToServer(SHARED_MEMORY_KEY) | ||
| connected = local_socket.waitForConnected(500) | ||
| if connected: | ||
| local_socket.disconnectFromServer() | ||
| return True | ||
| return False |
There was a problem hiding this comment.
_check_server_alive()的注释写的是“服务器是否有响应”,但当前实现只检查是否能在超时内建立连接(并未验证对端能处理/回应任何数据)。建议要么把注释/日志措辞改为“是否可连接/是否在监听”,要么实现一个简单的 ping(写入并等待对端读/回)来匹配“有响应”的语义。
| _activate_existing_instance() | ||
| return shared_memory, False | ||
| else: | ||
| logger.exception("无法附加到共享内存") | ||
| return shared_memory, False | ||
| logger.warning("无法附加到共享内存,尝试检测服务器状态") | ||
| if _check_server_alive(): | ||
| logger.info("检测到活跃的服务器,已有实例正在运行") | ||
| _activate_existing_instance() | ||
| return shared_memory, False |
There was a problem hiding this comment.
本 PR 代码中还删除了 requirements-windows.txt 和 requirements-linux.txt 两个依赖文件,但 PR 描述里未提及这一变更。若这是有意切换到 pyproject.toml/uv.lock 作为唯一依赖来源,建议在描述中补充说明(或拆分为独立 PR),以便评审者确认对打包/CI/文档没有影响。
修复内容
本 PR 包含两个独立的 bug 修复:
1. 修复抽奖动画期间学号显示错误 (Fixes #211)
问题描述:
在播放抽奖动画时,截图抓拍显示的学号超出了班级实际人数范围(如显示70号,但班里一共56人)。
根本原因:
lottery_manager.py中的draw_random函数在创建动画帧数据时,错误地使用了奖品ID而非学生ID。当奖池中有70个奖品但班级只有56名学生时,动画显示的"学号"就会超出实际学生范围。修复方案:
get_random_items函数,在选取学生时同时获取并存储学生IDdraw_random函数,使用学生ID替代奖品ID影响范围:
2. 修复单实例检测与本地服务器启动失败 (initiative_1)
问题描述:
应用程序在异常终止后重启时出现两个相关问题:
根本原因:
当进程异常退出时,
QSharedMemory和QLocalServer的资源可能处于不一致状态,导致新进程无法正常启动。在POSIX系统(Linux/macOS)上,
QSharedMemory使用System V或POSIX共享内存API,这些系统级资源在进程崩溃后不会自动清理,导致重启时shared_memory.create(1)失败。修复方案:
_check_server_alive函数检测本地服务器是否有响应_cleanup_stale_resources函数清理残留的socket资源_cleanup_stale_shared_memory函数清理残留的共享内存段(POSIX系统需要)check_single_instance函数,当无法附加共享内存时检测服务器状态setup_local_server函数,当 socket 地址被占用时清理残留资源后重试影响范围:
修改文件
app/common/lottery/lottery_manager.pyapp/core/single_instance.py测试建议
Issue #211 测试:
initiative_1 测试:
验证
所有修改已通过 ruff 代码检查。