信号触发关系
旧竞速纪录和新闻信号已移除。msuser 目前只维护录像计数与上传额度;新竞速榜由 speedranking 接收 VideoModel.post_save/post_delete,在事务提交后增量更新 Redis 或补位失效纪录。
speedranking 复用 videomanager 捕获的旧值。关注 player、level、mode、state、ongoing_tournament、bv、timems、right_ce、upload_time;提高成绩直接比较,变差/失去资格/删除时只重建由该录像保持的单项。类别迁移同时处理原玩家和新玩家,bvs、iqg 使用数据库保存的 GeneratedField;bv 或 timems 变化会触发这些派生指标的判断。标识绑定/解绑与比赛批量公开不触发保存信号,须显式调用 add_videos_to_speed_ranks / remove_videos_from_speed_ranks。
竞速入口同时协调 speedranking.saolei、speedranking.pb 与 speedranking.top:共用用户纪录读取和主要变更写入 pipeline,各自判断选优与补位。PB 按等级、3BV、普通/NF 分桶,日常比较编码 score;旧 member 的录像 id 来自用户 hash,按变更前、后的 member 排名确定范围,写入后只批量刷新该区间的 rank,加入或移除延伸至榜尾。top 各项保留最佳五条;只对已入选五条的失效或变差录像查库补位,写入后对变动小榜去重刷新锚点。单录像和批量更新、管理员修复、管理命令重建的错误统一记录上下文与堆栈后继续抛出,不使用 WATCH 或重试。
个人纪录的增量选优、补位查询和批量重建保持原有逻辑;仅在生成 Redis zset score 时使用四位小数 Bvs 和分钟级上传时间,并检查单项或总值的编码范围。超限仅移除对应 zset 条目,不触发个人纪录补位,hash 仍保存原始最佳成绩;总榜按总值独立判断。
top 原始十八项统一参与用户集合,并以变换后的均值作为降序索引。共同写入后先按已发布锚点局部更新该用户的软实力;实时锚点数值变化时发送 speedranking.top.events.soft_refresh_requested,由 top.signals 创建 task_refresh_soft_ranks。任务执行时有其他同路径 READY 任务就正常跳过,否则取得单机独占准入,九次加权合并后统一发布。相关 HTTP 写入口在事务前取得共享准入并覆盖 on_commit 回调;刷新期间新 HTTP 写请求返回有业务原因的 503,后台业务等待而不拒绝。接口、锁路径和运维限制见 back_end/saolei/speedranking/README.md。
NF 是独立维度,由 VideoModel.right_ce == 0 判断,不再使用模式 12。创建和删除时,NF 子计数与录像原模式的子计数同时增减;right_ce 为空不计入 NF。videomanager 捕获 right_ce 变化并更新队列;customranking 不需要 NF 信息,不监听此字段。批量转换旧模式后需显式刷新计数及缓存,步骤见 back_end/saolei/msuser/refactor.md。
效率榜由独立 effranking.signals 监听录像保存和删除,复用 _old_values 及 update_fields 判断影响范围。除资格、玩家、级别及上传时间外,还监控 bv/left_ce/right_ce/double_ce,不按 NF 分榜。提交后重读数据库生成的 Thrp,改善直接比较缓存,原纪录失效或变差才查库补位;回滚不更新 Redis。绑定/解绑标识和比赛公开显式调用 add_videos_to_eff_ranks / remove_videos_from_eff_ranks。异常记录上下文和堆栈后继续抛出,见 back_end/saolei/effranking/README.md。
| 图中名称 | 函数 |
|---|---|
| 捕获字段旧值 | capture_video_update |
| 比赛录像检测 | checkin_video_before_create |
| 刷新状态队列 | refresh_state_queue_on_video_save |
| 更新用户录像计数 | update_video_count_on_video_save / update_video_count_on_video_delete |
| 更新用户录像上限 | update_video_count_limit_on_video_save |
| 将比赛录像挂载到比赛 | add_created_video_to_checked_tournaments |
| 刷新pluck纪录 | refresh_custom_pluck_rank_on_video_save |
| 提交后更新效率纪录与必要补位 | effranking.signals.refresh_ranks_on_video_save |
| 提交后补位效率纪录 | effranking.signals.refresh_ranks_on_video_delete |
| 更新pluck榜缓存 | update_custom_pluck_cache_on_record_save |
| 删除pluck榜缓存 | update_custom_pluck_cache_on_record_delete |
| 更新比赛缓存 | update_cache_on_tournament_save |
| 删除比赛缓存 | update_cache_on_tournament_delete |
| 更新参赛缓存 | update_cache_on_participant_save |
| 刷新GSC历史最好 | update_best_score_on_gsc_participant_save |
| 刷新周赛历史最好 | update_best_score_on_weekly_participant_save |
| 重算GSC历史最好 | update_best_score_on_gsc_participant_delete |
| 重算周赛历史最好 | update_best_score_on_weekly_participant_delete |
| 删除参赛缓存 | remove_participant_cache_on_delete |
| 补录比赛录像 | add_existing_videos_to_participant_tournament |
录像计数排除比赛录像。创建时读取 ongoing_tournament;删除时在 pre_delete 中检查该标记及 Tournament.videos 关联,避免级联删除清除关联后误减计数。比赛公开不增加计数。已有数据可通过 refresh_video_counts 命令重算,包括补录到比赛的历史录像;上传数量上限仍由独立的 update_video_count_limit_on_video_save 维护。
Tournament / GSCTournament / WeeklyTournament 的保存信号分别绑定到同一个 update_cache_on_tournament_save 接收器。TournamentParticipant / GSCParticipant / WeeklyParticipant 的保存信号分别绑定到同一个 update_cache_on_participant_save 接收器。缓存删除信号只保留父类接收器;多表继承删除子类时会继续触发父表删除。历史最好成绩依赖子类 participant 的成绩字段,因此由 GSCParticipant / WeeklyParticipant 的保存和删除信号单独处理:保存时只比较当前 participant 与原 best,删除时才重算该用户历史 best。best 信号更新的是 TournamentUser 数据库汇总字段,需要和 participant 变更保持事务一致,因此不使用 transaction.on_commit。
