Skip to content

缓存结构 ​

本文记录项目当前使用的 Redis / Django cache 结构,以及缓存与数据库、API 之间的读写流向。数据库字段结构以各 app 的 models.py 为准,这里只记录缓存中实际保存的数据结构。

旧竞速排行榜及新闻的读写逻辑已移除,可运行python manage.py delete_legacy_speedranking_cache清理旧个人纪录hash、排行zset及news_queue。支持--dry-run预览,具体范围见管理命令文档。

旧 World 监控页面及其 CPU/网络 IO 采集已移除,不再读写历史采样。monitor APP 现在承载服务器页面的磁盘、任务、录像和内存统计 Ninja API,路径为 /api/monitor/diskusage、/api/monitor/tasksummary、/api/monitor/videosummary、/api/monitor/memoryusage;旧 /monitor/io_cpus/ 和 /monitor/capacity/ 不恢复。部署并停止旧采集进程后,可按固定名称清理 saolei_website Redis DB 中的五个遗留 key,无需遍历其他 key:

bash
redis-cli -n 0 DEL io_s_old io_r_old io_s_spds io_r_spds cpus

服务器内存统计 ​

GET /api/monitor/memoryusage 同时返回进程内存 memory 和 Redis 分配内存 redis。monitor/cache.py 通过 Django default Redis 缓存保存完整返回体,逻辑 key 为 api:monitor/memoryusage,TTL 300 秒。命中不重新采集、不读取用户 ID、不续期;到期后的首次请求重新计算。不新增 APScheduler 任务。

每块包含 status、UTC sampled_at、固定错误码 reason、非负整数 total_bytes 和固定分类 groups。进程按 uWSGI(含 master/workers)、本项目 APScheduler、Redis、MySQL、db_worker、其他进程聚合。Linux 统一采集 PSS,其他平台统一 RSS;RSS 可能重复计算共享页。合计仅覆盖进程驻留内存,主机总内存/可用内存单独放在 memory.host,不包含在图中合计内。本机 Redis 服务进程按进程名或可执行文件名汇总,Redis/MySQL 连接配置为远程或已知容器隔离时,进程块返回范围不足。

Redis 分类只读取业务代码直接确定的 DB 0 key,不执行 SCAN、scan_iter、KEYS 或排行榜成员枚举:

分类key 来源
PB 榜PBRankingCache.counts_key;固定 hash 的 HKEYS 经校验后构造小榜 key;从 UserProfile 主键顺序每批最多 1,000 个 ID 构造用户 hash key。元数据缺失不发现 key、不触发重建。
其他排行榜SpeedRankingCache(name, stats=RANK_STATS).keys、TopRankingCache().keys、四种自定义 pluck 配置的 rank/detail key、比赛用户榜 key 和积分时间 key;当前共 54 个 key。
最新录像newest_cache.key(newest_queue)。
其他INFO memory.used_memory 减去前三类;包含其他业务、会话、同实例 DB 1 通用缓存、孤立/历史/临时 key 和 Redis 开销,不枚举 DB 1。

所有已知 key 去重后以 pipeline(transaction=False) 每批最多 100 个执行 MEMORY USAGE ... SAMPLES 5,不存在的 key 为 0。该结果为估算,redis.estimated=true、redis.samples=5;总量为实例 used_memory,不同于进程 RSS/PSS。分类合计大于实例总量时不发布分布。两块共享 5 秒协作式采集预算,另限制最多 5,000 个进程和 50,000 个 key;阻塞中的 socket/查询仍受各自超时控制,因此 5 秒不是硬中断时限。

进程采集中退出的 PID 跳过;存活进程权限不足时整块不可用,并通过 memory.unreadable_processes 记录数量,不能当作零。不可用块的时间、总量和分类为 null,另一块可独立成功;完整结果仍缓存 300 秒,避免重复失败采集。缓存后端本身出错则请求失败,不绕过缓存继续采集。日志仅记录安全原因、耗时和数量,不记录 PID、命令行、key 名或业务值。上线需以实际 API 用户验证 Linux /proc 权限,并抽查冷缓存耗时、Redis 计量结果及缓存 TTL。前端可保留当前页面上次成功的图,明确标注旧数据及原采集时间。

总览 ​

独立的本地初始化脚本 dangerzone/init_local_test.py 会清空本地 saolei_website Redis 数据库(包含会话),然后根据导入的公开录像重建竞速榜(扫雷网普通/NF、PB 普通/NF、top 十八项及锚点)、效率 Thrp 榜、pluck 纪录缓存和录像状态队列。在 back_end/saolei 目录使用 python -m dangerzone.init_local_test 启动。只允许本地测试配置,并拒绝存在 .production 标记的环境;不注册 import_public_data 管理命令。详情及数据缺失限制见本地公开数据快照。

新竞速榜 speedranking ​

扫雷网规则使用 speedranking:{ranking_name}:records hash 保存个人纪录,使用 speedranking:{ranking_name}:{stat} zset 保存以玩家 id 为 member 的排序索引,由 speedranking.saolei.cache.SpeedRankingCache 管理。PB 是一般约定的例外:每个 (普通/NF, level, bv) 一个 zset,每个用户一个包含用时、录像 id 和 rank 的 hash,由 speedranking.pb.cache.PBRankingCache 管理。

共享缓存层提供连接及 pipeline,扫雷网、PB 和 top 的业务分别位于对应子目录。一次更新或每个批处理段共同读取用户纪录,独立判断后共同写入;PB 查询旧 score、刷新变化小榜的 rank,以及 top 更新锚点是依赖前序结果的后续批量阶段。必须补位的单项按各榜规则查询。

top 由 speedranking.top.cache.TopRankingCache 管理,包含用户前五明细、十八个原始索引、九个软实力/LSF 索引及锚点。缓存结构、后台发布与单机准入、前端启动快照约定统一见 back_end/saolei/speedranking/README.md。部署升级需要执行 top 重建命令,不能混用旧 score 编码。

排序编码、精度与数值范围、纪录更新及缓存升级约定统一维护在仓库的 back_end/saolei/speedranking/README.md,此处不再重复。重建命令用法见管理命令。

PB 只读接口不自动回源,初始化和修复用法见 PB 重建命令。前端 PB 排行页面已实现,分页上传时间直接由 zset score 解码,不增加查询或 hash 字段。

PB 另使用 speedranking:pb:counts hash 汇总各小榜人数,可通过 GET /api/speedranking/pb/counts 一次读取,随 rank 刷新同步更新;前端用于筛选网格的人数显示。已有缓存通过 PB 重建命令补齐。具体 field 及空榜约定见 app README。

管理员页面的“排行纪录重建” tab 可按大榜、小榜和用户 ID 修复单项缓存,对应接口为 POST /api/speedranking/admin/rebuild_record;具体更新范围和并发约定见上述 README。

效率榜 effranking ​

Thrp 的一个个人纪录 hash 和四个排序 zset 见下方数据结构表。编码、选优和事务边界统一见 back_end/saolei/effranking/README.md;首次部署及缓存丢失后执行 rebuild_eff_ranks,查询不自动回源。

cachecreate_account_link->accountlinkqueue_dbdelete_link->accountlinkqueue_dbdelete_link->accountlinkplatform_dbupdate_link->accountlinkplatform_dbview_saolei_import_one_video->task_dbview_saolei_import_one_video->videosaolei_dbview_saolei_import_one_video->video_dbview_saolei_import_one_video->video_filesview_saolei_import_videos->task_dbenqueue/deleteview_saolei_import_videos->accountlinkplatform_dbview_saolei_import_videos->task_saolei_video_import_bulkenqueuevideo_upload->video_dbcreate after is_completed checkvideo_upload->video_fileswrite after is_completed checkadd_identifier->custom_pluck_dbadd_identifier->identifier_dbadd_identifier->userms_dbdel_identifier->custom_pluck_dbdel_identifier->identifier_dbdel_identifier->userms_dbset_tournament->tournament_dbcancel_tournament->tournament_dbdelete_participant->participant_dbdelete (parent/subclass)reveal_video->video_dbsave ongoing_tournament=Falsecreate_gsc_participant->participant_dbregister_gsc_participant_identifier->identifier_dbregister_gsc_participant_identifier->userms_dbregister_gsc_participant_identifier->participant_dbregister_gsc_participant_identifier->video_dbcreate_weekly_participant->participant_dbupdate_user_profile->userprofile_dbupdate_user_avatar->userprofile_dbupdate_user_avatar->avatar_filesuser_retrieve->userprofile_dbuser_retrieve->email_otp_dbuser_register->userprofile_dbuser_register->email_otp_dbrefresh_captcha->captcha_dbget_email_captcha->captcha_dbcaptcha_db->user_logincaptcha_db->refresh_captchacaptcha_db->get_email_captchatask_db->view_saolei_import_one_videotask_db->view_saolei_import_videostask_db->view_saolei_get_import_listtask_db->view_saolei_get_import_summarytask_db->task_summary_cachetask_db->task_saolei_video_import_bulkread/deletetask_db->task_saolei_video_importstatus/readtask_db->task_gsc_finishstatus/readtask_db->task_gsc_refresh_beststatus/readtask_db->task_award_tournamentstatus/readtask_db->task_weekly_finishstatus/readtask_db->task_weekly_refresh_beststatus/readaccountlinkqueue_db->get_account_linksaccountlinkqueue_db->delete_linkaccountlinkplatform_db->get_account_linksaccountlinkplatform_db->update_linkaccountlinkplatform_db->view_saolei_import_one_videoaccountlinkplatform_db->view_saolei_import_videosaccountlinkplatform_db->view_saolei_get_import_listaccountlinkplatform_db->view_saolei_get_import_summaryaccountlinkplatform_db->task_saolei_video_import_bulkreadaccountlinkplatform_db->task_saolei_video_importFK readvideosaolei_db->view_saolei_import_one_videovideosaolei_db->view_saolei_import_videosvideosaolei_db->view_saolei_get_import_listvideosaolei_db->view_saolei_get_import_summaryvideosaolei_db->task_saolei_video_import_bulkread/writevideosaolei_db->task_saolei_video_importreadcustom_pluck_db->refresh_custom_pluck_rank_on_video_savereadcustom_pluck_db->update_custom_pluck_cache_on_record_savepost_savecustom_pluck_db->update_custom_pluck_cache_on_record_deletepost_deleteidentifier_db->get_participant_listidentifier_db->register_gsc_participant_identifieridentifier_db->update_cache_on_participant_saveFK readidentifier_db->task_saolei_video_importreaduserms_db->add_identifieruserms_db->del_identifieruserms_db->get_user_identifieruserms_db->update_user_profileuserms_db->update_user_avataruserms_db->user_loginuserms_db->user_retrieveuserms_db->user_registeruserms_db->update_video_count_on_video_saveO2O readuserms_db->update_video_count_limit_on_video_saveO2O readuserms_db->update_video_count_on_video_deleteO2O readuserms_db->task_saolei_video_importO2O readtournament_db->get_tournament_listtournament_db->get_tournamenttournament_db->set_tournamenttournament_db->cancel_tournamenttournament_db->get_participant_listtournament_db->delete_participanthost_id read (join)tournament_db->get_participant_videostournament_db->download_all_videostournament_db->download_videos_participanttournament_db->get_gsc_resultstournament_db->create_gsc_participanttournament_db->register_gsc_participant_identifiertournament_db->get_weekly_resultstournament_db->create_weekly_participanttournament_db->update_video_count_on_video_deletem2m existstournament_db->checkin_video_before_createquery readtournament_db->update_cache_on_tournament_deletepost_deletetournament_db->update_cache_on_tournament_savepost_savetournament_db->update_cache_on_tournament_savesubclass readtournament_db->update_cache_on_participant_saveFK/m2m readtournament_db->update_best_score_on_gsc_participant_saveFK/subclass readtournament_db->update_best_score_on_weekly_participant_saveFK/subclass readtournament_db->update_best_score_on_gsc_participant_deleteFK/subclass readtournament_db->update_best_score_on_weekly_participant_deleteFK/subclass readtournament_db->task_gsc_finishread/writetournament_db->task_gsc_refresh_bestreadtournament_db->task_award_tournamentreadtournament_db->task_weekly_finishread/writetournament_db->task_weekly_refresh_bestreadparticipant_db->get_participant_listparticipant_db->delete_participantreadparticipant_db->get_participant_videosparticipant_db->get_gsc_resultsparticipant_db->register_gsc_participant_identifierparticipant_db->get_weekly_resultsparticipant_db->update_cache_on_participant_savepost_saveparticipant_db->update_best_score_on_gsc_participant_savepost_saveparticipant_db->update_best_score_on_weekly_participant_savepost_saveparticipant_db->update_best_score_on_gsc_participant_deletepost_deleteparticipant_db->update_best_score_on_gsc_participant_deletequery bestparticipant_db->update_best_score_on_weekly_participant_deletepost_deleteparticipant_db->update_best_score_on_weekly_participant_deletequery bestparticipant_db->remove_participant_cache_on_deletepost_deleteparticipant_db->task_gsc_finishread/write/deleteparticipant_db->task_gsc_refresh_bestreadparticipant_db->task_award_tournamentread/write rank_scoreparticipant_db->task_weekly_finishread/write/deleteparticipant_db->task_weekly_refresh_bestreadtournament_user_db->update_best_score_on_gsc_participant_saveread/createtournament_user_db->update_best_score_on_weekly_participant_saveread/createtournament_user_db->update_best_score_on_gsc_participant_deletereadtournament_user_db->update_best_score_on_weekly_participant_deletereadtournament_user_db->task_gsc_finishensure_tournament_users: readtournament_user_db->task_gsc_refresh_bestread/write besttournament_user_db->task_award_tournamentread/write scoretournament_user_db->task_weekly_finishensure_tournament_users: readtournament_user_db->task_weekly_refresh_bestread/write besttournament_user_db->rebuild_tournament_current_score_cacheread score_current / last_updateduserprofile_db->view_saolei_get_import_listuserprofile_db->set_tournamentuserprofile_db->cancel_tournamentuserprofile_db->get_participant_videosuserprofile_db->download_videos_participantuserprofile_db->get_gsc_resultsuserprofile_db->create_gsc_participantuserprofile_db->register_gsc_participant_identifieruserprofile_db->create_weekly_participantuserprofile_db->get_user_infouserprofile_db->get_user_info_bulkuserprofile_db->get_user_info_updateduserprofile_db->get_user_identifieruserprofile_db->get_user_avataruserprofile_db->get_user_videosuserprofile_db->update_user_profileuserprofile_db->update_user_avataruserprofile_db->user_loginuserprofile_db->user_retrieveuserprofile_db->user_registeruserprofile_db->check_collisionuserprofile_db->get_softwareuserprofile_db->video_previewuserprofile_db->video_downloaduserprofile_db->video_queryuserprofile_db->video_query_by_iduserprofile_db->memory_usage_cachePB user IDs on cache missuserprofile_db->refresh_state_queue_on_video_saveFK readuserprofile_db->update_video_count_on_video_saveFK readuserprofile_db->update_video_count_limit_on_video_saveFK readuserprofile_db->update_video_count_on_video_deleteFK readuserprofile_db->refresh_custom_pluck_rank_on_video_saveFK readuserprofile_db->task_saolei_video_importO2O reademail_otp_db->user_retrieveemail_otp_db->user_registervideo_db->view_saolei_import_one_videovideo_db->add_identifiervideo_db->del_identifiervideo_db->get_participant_videosvideo_db->reveal_videoread / lock / owner checkvideo_db->download_all_videosvideo_db->download_videos_participantvideo_db->get_user_videosvideo_db->user_loginvideo_db->user_retrievevideo_db->user_registervideo_db->get_review_queuevideo_db->get_video_info_bulkvideo_db->get_video_detail_bulkvideo_db->get_softwarevideo_db->video_previewvideo_db->video_downloadvideo_db->video_queryvideo_db->video_query_by_idvideo_db->disk_usage_cachevideo_db->video_summary_cachevideo_db->capture_video_updatepre_savevideo_db->capture_video_updatereadvideo_db->refresh_state_queue_on_video_savepost_savevideo_db->refresh_state_queue_on_video_saveO2O readvideo_db->update_video_count_on_video_savepost_savevideo_db->update_video_count_limit_on_video_savepost_savevideo_db->update_video_count_on_video_deletepre_deletevideo_db->refresh_custom_pluck_rank_on_video_savepost_savevideo_db->refresh_custom_pluck_rank_on_video_saveread bestvideo_db->update_custom_pluck_cache_on_record_saveFK readvideo_db->checkin_video_before_createpre_savevideo_db->checkin_video_before_createO2O readvideo_db->add_created_video_to_checked_tournamentspost_savevideo_db->update_cache_on_participant_savequery readvideo_db->task_saolei_video_importcollision/readvideo_db->task_gsc_finishscore: OFFICIAL only; reveal: read/writevideo_db->task_weekly_finishscore: OFFICIAL only; reveal: read/writetask_summary_cache->task_summarydisk_usage_cache->disk_usagevideo_summary_cache->video_summarymemory_usage_cache->memory_usagepluck_rank_cache->pluck_rankpluck_rank_cache->player_pluck_recordspluck_detail_cache->pluck_rankpluck_detail_cache->player_pluck_recordsnewest_cache->newest_queuenewest_cache->memory_usage_cacheMEMORY USAGEfreeze_cache->freeze_queuetournament_cache->get_tournament_listtournament_cache->get_tournament_newsparticipant_cache->checkin_video_before_createreadparticipant_cache->update_cache_on_tournament_deletescan/readparticipant_cache->update_cache_on_tournament_savescan/readparticipant_cache->update_cache_on_participant_savereadparticipant_cache->remove_participant_cache_on_deletereadtournament_user_rank_cache->task_award_tournamentEXISTS only if reference missingtournament_user_rank_cache->refresh_tournament_score_referenceZUNIONSTORE score_currenttournament_user_score_time_cache->task_award_tournamentread reference timetournament_user_score_time_cache->refresh_tournament_score_referenceread old anchorvideo_files->view_saolei_import_one_videovideo_files->download_all_videosvideo_files->download_videos_participantvideo_files->video_previewvideo_files->video_downloadvideo_files->task_saolei_video_importreadavatar_files->get_user_avatarrefresh_state_queue_on_video_save->newest_cachewrite/deleterefresh_state_queue_on_video_save->freeze_cachewrite/deleterefresh_state_queue_on_video_save->review_cachewrite/deleteupdate_video_count_on_video_save->userms_dbwriteupdate_video_count_limit_on_video_save->userms_dbwriteupdate_video_count_on_video_delete->userms_dbwriterefresh_custom_pluck_rank_on_video_save->custom_pluck_dbwrite/deleteupdate_custom_pluck_cache_on_record_save->pluck_rank_cachewriteupdate_custom_pluck_cache_on_record_save->pluck_detail_cachewriteupdate_custom_pluck_cache_on_record_delete->pluck_rank_cachedeleteupdate_custom_pluck_cache_on_record_delete->pluck_detail_cachedeletecheckin_video_before_create->video_dbwrite fieldadd_created_video_to_checked_tournaments->tournament_dbm2m writeupdate_cache_on_tournament_delete->tournament_cachedeleteupdate_cache_on_tournament_delete->participant_cachewrite/deleteupdate_cache_on_tournament_save->tournament_cachewrite/deleteupdate_cache_on_tournament_save->participant_cachewrite/deleteupdate_cache_on_participant_save->tournament_dbm2m writeupdate_cache_on_participant_save->participant_cachewrite/deleteupdate_best_score_on_gsc_participant_save->tournament_user_dbwrite bestupdate_best_score_on_weekly_participant_save->tournament_user_dbwrite bestupdate_best_score_on_gsc_participant_delete->tournament_user_dbwrite bestupdate_best_score_on_weekly_participant_delete->tournament_user_dbwrite bestremove_participant_cache_on_delete->participant_cachewrite/deletetask_saolei_video_import_bulk->task_dbenqueue/deletetask_saolei_video_import_bulk->videosaolei_dbwritetask_saolei_video_import_bulk->task_saolei_video_importenqueue eachtask_saolei_video_import->task_dbstatus writetask_saolei_video_import->videosaolei_dbwritetask_saolei_video_import->userms_dbcreatetask_saolei_video_import->video_dbwritetask_saolei_video_import->video_fileswritetask_gsc_finish->tournament_dbstate writetask_gsc_finish->participant_dbscore/ranktask_gsc_finish->tournament_user_dbensure_tournament_users: create missingtask_gsc_finish->pluck_rank_cacherestore plucktask_gsc_finish->pluck_detail_cacherestore plucktask_gsc_finish->newest_cacherestore queuestask_gsc_finish->freeze_cacherestore queuestask_gsc_finish->review_cacherestore queuestask_gsc_finish->task_gsc_refresh_bestenqueuetask_gsc_finish->task_award_tournamentenqueuetask_gsc_refresh_best->tournament_user_dbensure_tournament_users / refresh_gsc_best_scorestask_gsc_refresh_best->tournament_user_rank_cachewrite best zsettask_award_tournament->tournament_user_dbensure_tournament_users / award_tournament_rank_scorestask_award_tournament->tournament_user_rank_cachewrite score zsetstask_award_tournament->tournament_user_score_time_cacheinit only when emptytask_weekly_finish->tournament_dbstate writetask_weekly_finish->participant_dbscore/ranktask_weekly_finish->tournament_user_dbensure_tournament_users: create missingtask_weekly_finish->pluck_rank_cacherestore plucktask_weekly_finish->pluck_detail_cacherestore plucktask_weekly_finish->newest_cacherestore queuestask_weekly_finish->freeze_cacherestore queuestask_weekly_finish->review_cacherestore queuestask_weekly_finish->task_award_tournamentenqueuetask_weekly_finish->task_weekly_refresh_bestenqueuetask_weekly_refresh_best->tournament_user_dbensure_tournament_users / refresh_weekly_best_scorestask_weekly_refresh_best->tournament_user_rank_cachewrite best zsetrefresh_tournament_score_reference->tournament_user_rank_cacheannual rescalerefresh_tournament_score_reference->tournament_user_score_time_cacheset annual anchorrebuild_tournament_current_score_cache->tournament_user_rank_cacheatomic rebuild score_current onlyrebuild_tournament_current_score_cache->tournament_user_score_time_cacheset annual anchorget_account_links/api/accountlink/{user_id}create_account_link/api/accountlink/create/delete_link/accountlink/delete/update_link/accountlink/update/view_saolei_import_one_video/accountlink/saolei_import_video/view_saolei_import_videos/accountlink/saolei_import_videos/view_saolei_get_import_list/accountlink/saolei/videolist/get/view_saolei_get_import_summary/accountlink/saolei/videoimport/stat/task_summary/api/monitor/tasksummarydisk_usage/api/monitor/diskusagevideo_summary/api/monitor/videosummarymemory_usage/api/monitor/memoryusagevideo_upload/common/uploadvideo/pluck_rank/api/customranking/pluckplayer_pluck_records/api/customranking/pluck/playeradd_identifier/identifier/add/del_identifier/identifier/del/get_tournament_list/api/tournament/get_listget_tournament/api/tournament/getset_tournament/api/tournament/setcancel_tournament/api/tournament/cancelget_participant_list/api/tournament/participantsdelete_participantDELETE /api/tournament/participant/{participant_id}get_participant_videos/api/tournament/get_videos/participantreveal_videoPOST /api/tournament/video/{video_id}/revealget_tournament_news/api/tournament/get_newsdownload_all_videos/api/tournament/downloaddownload_videos_participant/api/tournament/download/participantget_gsc_results/api/tournament/gsc/resultscreate_gsc_participant/api/tournament/gsc/participantregister_gsc_participant_identifier/api/tournament/gsc/participant/identifierget_weekly_results/api/tournament/weekly/resultscreate_weekly_participant/api/tournament/weekly/participantget_user_info/api/userprofile/info/{user_id}get_user_info_bulk/api/userprofile/infobulkget_user_info_updated/api/userprofile/infoupdatedget_user_identifier/api/userprofile/identifierget_user_avatar/api/userprofile/avatar/{user_id}get_user_videos/api/userprofile/videolistupdate_user_profile/api/userprofile/update_profileupdate_user_avatar/api/userprofile/update_avataruser_login/userprofile/login/user_retrieve/userprofile/retrieve/user_register/userprofile/register/check_collision/userprofile/checkcollision/refresh_captcha/userprofile/refresh_captcha/get_email_captcha/userprofile/get_email_captcha/get_review_queue/api/video/review_queueget_video_info_bulk/api/video/infobulkget_video_detail_bulk/api/video/detailbulkget_software/video/get_software/video_preview/video/preview/video_download/video/download/video_query/video/query/video_query_by_id/video/query_by_id/newest_queue/video/newest_queue/freeze_queue/video/freeze_queue/captcha_dbCaptchaStoretask_dbDBTaskResultaccountlinkqueue_dbAccountLinkQueueplatform accountsaccountlinkplatform_dbAccountSaoleiAccountMinesweeperGamesAccountBilibiliAccountWorldOfMinesweeperAccountQQvideosaolei_dbVideoSaoleicustom_pluck_dbCustomPluckRecordidentifier_dbIdentifieruserms_dbUserMStournament_dbTournamentGSCTournamentWeeklyTournamentparticipant_dbTournamentParticipantGSCParticipantWeeklyParticipanttournament_user_dbTournamentUseruserprofile_dbUserProfileemail_otp_dbEmailVerifyRecordvideo_dbVideoModelExpandVideoModeltask_summary_cacheapi:monitor/tasksummarydisk_usage_cacheapi:monitor/diskusagevideo_summary_cacheapi:monitor/videosummarymemory_usage_cacheapi:monitor/memoryusageTTL 300spluck_rank_cachecustomranking:pluck:{level}:rankzsetpluck_detail_cachecustomranking:pluck:{level}:detailhashnewest_cachenewest_queuehashfreeze_cachefreeze_queuehashreview_cachereview_queuehashtournament_cachetournament:normalhashsubclass + dataparticipant_cachetournament:normal:participantshashtournament_user_rank_cachetournament:user:{field}zsetmember = user_idtournament_user_score_time_cachetournament:user:score_current:last_updatedstring年度锚点:1 月 1 日 UTCmonitor_summary_cacheapi:monitor/*TTL 300svideo_filesvideo filesavatar_filesavatar filescapture_video_updatecapture_video_updaterefresh_state_queue_on_video_saverefresh_state_queue_on_video_saveupdate_video_count_on_video_saveupdate_video_count_on_video_saveupdate_video_count_limit_on_video_saveupdate_video_count_limit_on_video_saveupdate_video_count_on_video_deleteupdate_video_count_on_video_deleterefresh_custom_pluck_rank_on_video_saverefresh_custom_pluck_rank_on_video_saveupdate_custom_pluck_cache_on_record_saveupdate_custom_pluck_cache_on_record_saveupdate_custom_pluck_cache_on_record_deleteupdate_custom_pluck_cache_on_record_deletecheckin_video_before_createcheckin_video_before_createadd_created_video_to_checked_tournamentsadd_created_video_to_checked_tournamentsupdate_cache_on_tournament_deleteupdate_cache_on_tournament_deleteupdate_cache_on_tournament_saveupdate_cache_on_tournament_saveupdate_cache_on_participant_saveupdate_cache_on_participant_saveupdate_best_score_on_gsc_participant_saveupdate_best_score_on_gsc_participant_saveupdate_best_score_on_weekly_participant_saveupdate_best_score_on_weekly_participant_saveupdate_best_score_on_gsc_participant_deleteupdate_best_score_on_gsc_participant_deleteupdate_best_score_on_weekly_participant_deleteupdate_best_score_on_weekly_participant_deleteremove_participant_cache_on_deleteremove_participant_cache_on_deletetask_saolei_video_import_bulktask_saolei_video_import_bulktask_saolei_video_importtask_saolei_video_importtask_gsc_finishtask_gsc_finishtask_gsc_refresh_besttask_gsc_refresh_besttask_award_tournamenttask_award_tournamenttask_weekly_finishtask_weekly_finishtask_weekly_refresh_besttask_weekly_refresh_bestrefresh_tournament_score_referenceAPSchedulerrefresh_tournament_score_referencerebuild_tournament_current_score_cachemanage.pyrebuild_tournament_current_score_cache
cachecreate_account_link->accountlinkqueue_dbdelete_link->accountlinkqueue_dbdelete_link->accountlinkplatform_dbupdate_link->accountlinkplatform_dbview_saolei_import_one_video->task_dbview_saolei_import_one_video->videosaolei_dbview_saolei_import_one_video->video_dbview_saolei_import_one_video->video_filesview_saolei_import_videos->task_dbenqueue/deleteview_saolei_import_videos->accountlinkplatform_dbview_saolei_import_videos->task_saolei_video_import_bulkenqueuevideo_upload->video_dbcreate after is_completed checkvideo_upload->video_fileswrite after is_completed checkadd_identifier->custom_pluck_dbadd_identifier->identifier_dbadd_identifier->userms_dbdel_identifier->custom_pluck_dbdel_identifier->identifier_dbdel_identifier->userms_dbset_tournament->tournament_dbcancel_tournament->tournament_dbdelete_participant->participant_dbdelete (parent/subclass)reveal_video->video_dbsave ongoing_tournament=Falsecreate_gsc_participant->participant_dbregister_gsc_participant_identifier->identifier_dbregister_gsc_participant_identifier->userms_dbregister_gsc_participant_identifier->participant_dbregister_gsc_participant_identifier->video_dbcreate_weekly_participant->participant_dbupdate_user_profile->userprofile_dbupdate_user_avatar->userprofile_dbupdate_user_avatar->avatar_filesuser_retrieve->userprofile_dbuser_retrieve->email_otp_dbuser_register->userprofile_dbuser_register->email_otp_dbrefresh_captcha->captcha_dbget_email_captcha->captcha_dbcaptcha_db->user_logincaptcha_db->refresh_captchacaptcha_db->get_email_captchatask_db->view_saolei_import_one_videotask_db->view_saolei_import_videostask_db->view_saolei_get_import_listtask_db->view_saolei_get_import_summarytask_db->task_summary_cachetask_db->task_saolei_video_import_bulkread/deletetask_db->task_saolei_video_importstatus/readtask_db->task_gsc_finishstatus/readtask_db->task_gsc_refresh_beststatus/readtask_db->task_award_tournamentstatus/readtask_db->task_weekly_finishstatus/readtask_db->task_weekly_refresh_beststatus/readaccountlinkqueue_db->get_account_linksaccountlinkqueue_db->delete_linkaccountlinkplatform_db->get_account_linksaccountlinkplatform_db->update_linkaccountlinkplatform_db->view_saolei_import_one_videoaccountlinkplatform_db->view_saolei_import_videosaccountlinkplatform_db->view_saolei_get_import_listaccountlinkplatform_db->view_saolei_get_import_summaryaccountlinkplatform_db->task_saolei_video_import_bulkreadaccountlinkplatform_db->task_saolei_video_importFK readvideosaolei_db->view_saolei_import_one_videovideosaolei_db->view_saolei_import_videosvideosaolei_db->view_saolei_get_import_listvideosaolei_db->view_saolei_get_import_summaryvideosaolei_db->task_saolei_video_import_bulkread/writevideosaolei_db->task_saolei_video_importreadcustom_pluck_db->refresh_custom_pluck_rank_on_video_savereadcustom_pluck_db->update_custom_pluck_cache_on_record_savepost_savecustom_pluck_db->update_custom_pluck_cache_on_record_deletepost_deleteidentifier_db->get_participant_listidentifier_db->register_gsc_participant_identifieridentifier_db->update_cache_on_participant_saveFK readidentifier_db->task_saolei_video_importreaduserms_db->add_identifieruserms_db->del_identifieruserms_db->get_user_identifieruserms_db->update_user_profileuserms_db->update_user_avataruserms_db->user_loginuserms_db->user_retrieveuserms_db->user_registeruserms_db->update_video_count_on_video_saveO2O readuserms_db->update_video_count_limit_on_video_saveO2O readuserms_db->update_video_count_on_video_deleteO2O readuserms_db->task_saolei_video_importO2O readtournament_db->get_tournament_listtournament_db->get_tournamenttournament_db->set_tournamenttournament_db->cancel_tournamenttournament_db->get_participant_listtournament_db->delete_participanthost_id read (join)tournament_db->get_participant_videostournament_db->download_all_videostournament_db->download_videos_participanttournament_db->get_gsc_resultstournament_db->create_gsc_participanttournament_db->register_gsc_participant_identifiertournament_db->get_weekly_resultstournament_db->create_weekly_participanttournament_db->update_video_count_on_video_deletem2m existstournament_db->checkin_video_before_createquery readtournament_db->update_cache_on_tournament_deletepost_deletetournament_db->update_cache_on_tournament_savepost_savetournament_db->update_cache_on_tournament_savesubclass readtournament_db->update_cache_on_participant_saveFK/m2m readtournament_db->update_best_score_on_gsc_participant_saveFK/subclass readtournament_db->update_best_score_on_weekly_participant_saveFK/subclass readtournament_db->update_best_score_on_gsc_participant_deleteFK/subclass readtournament_db->update_best_score_on_weekly_participant_deleteFK/subclass readtournament_db->task_gsc_finishread/writetournament_db->task_gsc_refresh_bestreadtournament_db->task_award_tournamentreadtournament_db->task_weekly_finishread/writetournament_db->task_weekly_refresh_bestreadparticipant_db->get_participant_listparticipant_db->delete_participantreadparticipant_db->get_participant_videosparticipant_db->get_gsc_resultsparticipant_db->register_gsc_participant_identifierparticipant_db->get_weekly_resultsparticipant_db->update_cache_on_participant_savepost_saveparticipant_db->update_best_score_on_gsc_participant_savepost_saveparticipant_db->update_best_score_on_weekly_participant_savepost_saveparticipant_db->update_best_score_on_gsc_participant_deletepost_deleteparticipant_db->update_best_score_on_gsc_participant_deletequery bestparticipant_db->update_best_score_on_weekly_participant_deletepost_deleteparticipant_db->update_best_score_on_weekly_participant_deletequery bestparticipant_db->remove_participant_cache_on_deletepost_deleteparticipant_db->task_gsc_finishread/write/deleteparticipant_db->task_gsc_refresh_bestreadparticipant_db->task_award_tournamentread/write rank_scoreparticipant_db->task_weekly_finishread/write/deleteparticipant_db->task_weekly_refresh_bestreadtournament_user_db->update_best_score_on_gsc_participant_saveread/createtournament_user_db->update_best_score_on_weekly_participant_saveread/createtournament_user_db->update_best_score_on_gsc_participant_deletereadtournament_user_db->update_best_score_on_weekly_participant_deletereadtournament_user_db->task_gsc_finishensure_tournament_users: readtournament_user_db->task_gsc_refresh_bestread/write besttournament_user_db->task_award_tournamentread/write scoretournament_user_db->task_weekly_finishensure_tournament_users: readtournament_user_db->task_weekly_refresh_bestread/write besttournament_user_db->rebuild_tournament_current_score_cacheread score_current / last_updateduserprofile_db->view_saolei_get_import_listuserprofile_db->set_tournamentuserprofile_db->cancel_tournamentuserprofile_db->get_participant_videosuserprofile_db->download_videos_participantuserprofile_db->get_gsc_resultsuserprofile_db->create_gsc_participantuserprofile_db->register_gsc_participant_identifieruserprofile_db->create_weekly_participantuserprofile_db->get_user_infouserprofile_db->get_user_info_bulkuserprofile_db->get_user_info_updateduserprofile_db->get_user_identifieruserprofile_db->get_user_avataruserprofile_db->get_user_videosuserprofile_db->update_user_profileuserprofile_db->update_user_avataruserprofile_db->user_loginuserprofile_db->user_retrieveuserprofile_db->user_registeruserprofile_db->check_collisionuserprofile_db->get_softwareuserprofile_db->video_previewuserprofile_db->video_downloaduserprofile_db->video_queryuserprofile_db->video_query_by_iduserprofile_db->memory_usage_cachePB user IDs on cache missuserprofile_db->refresh_state_queue_on_video_saveFK readuserprofile_db->update_video_count_on_video_saveFK readuserprofile_db->update_video_count_limit_on_video_saveFK readuserprofile_db->update_video_count_on_video_deleteFK readuserprofile_db->refresh_custom_pluck_rank_on_video_saveFK readuserprofile_db->task_saolei_video_importO2O reademail_otp_db->user_retrieveemail_otp_db->user_registervideo_db->view_saolei_import_one_videovideo_db->add_identifiervideo_db->del_identifiervideo_db->get_participant_videosvideo_db->reveal_videoread / lock / owner checkvideo_db->download_all_videosvideo_db->download_videos_participantvideo_db->get_user_videosvideo_db->user_loginvideo_db->user_retrievevideo_db->user_registervideo_db->get_review_queuevideo_db->get_video_info_bulkvideo_db->get_video_detail_bulkvideo_db->get_softwarevideo_db->video_previewvideo_db->video_downloadvideo_db->video_queryvideo_db->video_query_by_idvideo_db->disk_usage_cachevideo_db->video_summary_cachevideo_db->capture_video_updatepre_savevideo_db->capture_video_updatereadvideo_db->refresh_state_queue_on_video_savepost_savevideo_db->refresh_state_queue_on_video_saveO2O readvideo_db->update_video_count_on_video_savepost_savevideo_db->update_video_count_limit_on_video_savepost_savevideo_db->update_video_count_on_video_deletepre_deletevideo_db->refresh_custom_pluck_rank_on_video_savepost_savevideo_db->refresh_custom_pluck_rank_on_video_saveread bestvideo_db->update_custom_pluck_cache_on_record_saveFK readvideo_db->checkin_video_before_createpre_savevideo_db->checkin_video_before_createO2O readvideo_db->add_created_video_to_checked_tournamentspost_savevideo_db->update_cache_on_participant_savequery readvideo_db->task_saolei_video_importcollision/readvideo_db->task_gsc_finishscore: OFFICIAL only; reveal: read/writevideo_db->task_weekly_finishscore: OFFICIAL only; reveal: read/writetask_summary_cache->task_summarydisk_usage_cache->disk_usagevideo_summary_cache->video_summarymemory_usage_cache->memory_usagepluck_rank_cache->pluck_rankpluck_rank_cache->player_pluck_recordspluck_detail_cache->pluck_rankpluck_detail_cache->player_pluck_recordsnewest_cache->newest_queuenewest_cache->memory_usage_cacheMEMORY USAGEfreeze_cache->freeze_queuetournament_cache->get_tournament_listtournament_cache->get_tournament_newsparticipant_cache->checkin_video_before_createreadparticipant_cache->update_cache_on_tournament_deletescan/readparticipant_cache->update_cache_on_tournament_savescan/readparticipant_cache->update_cache_on_participant_savereadparticipant_cache->remove_participant_cache_on_deletereadtournament_user_rank_cache->task_award_tournamentEXISTS only if reference missingtournament_user_rank_cache->refresh_tournament_score_referenceZUNIONSTORE score_currenttournament_user_score_time_cache->task_award_tournamentread reference timetournament_user_score_time_cache->refresh_tournament_score_referenceread old anchorvideo_files->view_saolei_import_one_videovideo_files->download_all_videosvideo_files->download_videos_participantvideo_files->video_previewvideo_files->video_downloadvideo_files->task_saolei_video_importreadavatar_files->get_user_avatarrefresh_state_queue_on_video_save->newest_cachewrite/deleterefresh_state_queue_on_video_save->freeze_cachewrite/deleterefresh_state_queue_on_video_save->review_cachewrite/deleteupdate_video_count_on_video_save->userms_dbwriteupdate_video_count_limit_on_video_save->userms_dbwriteupdate_video_count_on_video_delete->userms_dbwriterefresh_custom_pluck_rank_on_video_save->custom_pluck_dbwrite/deleteupdate_custom_pluck_cache_on_record_save->pluck_rank_cachewriteupdate_custom_pluck_cache_on_record_save->pluck_detail_cachewriteupdate_custom_pluck_cache_on_record_delete->pluck_rank_cachedeleteupdate_custom_pluck_cache_on_record_delete->pluck_detail_cachedeletecheckin_video_before_create->video_dbwrite fieldadd_created_video_to_checked_tournaments->tournament_dbm2m writeupdate_cache_on_tournament_delete->tournament_cachedeleteupdate_cache_on_tournament_delete->participant_cachewrite/deleteupdate_cache_on_tournament_save->tournament_cachewrite/deleteupdate_cache_on_tournament_save->participant_cachewrite/deleteupdate_cache_on_participant_save->tournament_dbm2m writeupdate_cache_on_participant_save->participant_cachewrite/deleteupdate_best_score_on_gsc_participant_save->tournament_user_dbwrite bestupdate_best_score_on_weekly_participant_save->tournament_user_dbwrite bestupdate_best_score_on_gsc_participant_delete->tournament_user_dbwrite bestupdate_best_score_on_weekly_participant_delete->tournament_user_dbwrite bestremove_participant_cache_on_delete->participant_cachewrite/deletetask_saolei_video_import_bulk->task_dbenqueue/deletetask_saolei_video_import_bulk->videosaolei_dbwritetask_saolei_video_import_bulk->task_saolei_video_importenqueue eachtask_saolei_video_import->task_dbstatus writetask_saolei_video_import->videosaolei_dbwritetask_saolei_video_import->userms_dbcreatetask_saolei_video_import->video_dbwritetask_saolei_video_import->video_fileswritetask_gsc_finish->tournament_dbstate writetask_gsc_finish->participant_dbscore/ranktask_gsc_finish->tournament_user_dbensure_tournament_users: create missingtask_gsc_finish->pluck_rank_cacherestore plucktask_gsc_finish->pluck_detail_cacherestore plucktask_gsc_finish->newest_cacherestore queuestask_gsc_finish->freeze_cacherestore queuestask_gsc_finish->review_cacherestore queuestask_gsc_finish->task_gsc_refresh_bestenqueuetask_gsc_finish->task_award_tournamentenqueuetask_gsc_refresh_best->tournament_user_dbensure_tournament_users / refresh_gsc_best_scorestask_gsc_refresh_best->tournament_user_rank_cachewrite best zsettask_award_tournament->tournament_user_dbensure_tournament_users / award_tournament_rank_scorestask_award_tournament->tournament_user_rank_cachewrite score zsetstask_award_tournament->tournament_user_score_time_cacheinit only when emptytask_weekly_finish->tournament_dbstate writetask_weekly_finish->participant_dbscore/ranktask_weekly_finish->tournament_user_dbensure_tournament_users: create missingtask_weekly_finish->pluck_rank_cacherestore plucktask_weekly_finish->pluck_detail_cacherestore plucktask_weekly_finish->newest_cacherestore queuestask_weekly_finish->freeze_cacherestore queuestask_weekly_finish->review_cacherestore queuestask_weekly_finish->task_award_tournamentenqueuetask_weekly_finish->task_weekly_refresh_bestenqueuetask_weekly_refresh_best->tournament_user_dbensure_tournament_users / refresh_weekly_best_scorestask_weekly_refresh_best->tournament_user_rank_cachewrite best zsetrefresh_tournament_score_reference->tournament_user_rank_cacheannual rescalerefresh_tournament_score_reference->tournament_user_score_time_cacheset annual anchorrebuild_tournament_current_score_cache->tournament_user_rank_cacheatomic rebuild score_current onlyrebuild_tournament_current_score_cache->tournament_user_score_time_cacheset annual anchorget_account_links/api/accountlink/{user_id}create_account_link/api/accountlink/create/delete_link/accountlink/delete/update_link/accountlink/update/view_saolei_import_one_video/accountlink/saolei_import_video/view_saolei_import_videos/accountlink/saolei_import_videos/view_saolei_get_import_list/accountlink/saolei/videolist/get/view_saolei_get_import_summary/accountlink/saolei/videoimport/stat/task_summary/api/monitor/tasksummarydisk_usage/api/monitor/diskusagevideo_summary/api/monitor/videosummarymemory_usage/api/monitor/memoryusagevideo_upload/common/uploadvideo/pluck_rank/api/customranking/pluckplayer_pluck_records/api/customranking/pluck/playeradd_identifier/identifier/add/del_identifier/identifier/del/get_tournament_list/api/tournament/get_listget_tournament/api/tournament/getset_tournament/api/tournament/setcancel_tournament/api/tournament/cancelget_participant_list/api/tournament/participantsdelete_participantDELETE /api/tournament/participant/{participant_id}get_participant_videos/api/tournament/get_videos/participantreveal_videoPOST /api/tournament/video/{video_id}/revealget_tournament_news/api/tournament/get_newsdownload_all_videos/api/tournament/downloaddownload_videos_participant/api/tournament/download/participantget_gsc_results/api/tournament/gsc/resultscreate_gsc_participant/api/tournament/gsc/participantregister_gsc_participant_identifier/api/tournament/gsc/participant/identifierget_weekly_results/api/tournament/weekly/resultscreate_weekly_participant/api/tournament/weekly/participantget_user_info/api/userprofile/info/{user_id}get_user_info_bulk/api/userprofile/infobulkget_user_info_updated/api/userprofile/infoupdatedget_user_identifier/api/userprofile/identifierget_user_avatar/api/userprofile/avatar/{user_id}get_user_videos/api/userprofile/videolistupdate_user_profile/api/userprofile/update_profileupdate_user_avatar/api/userprofile/update_avataruser_login/userprofile/login/user_retrieve/userprofile/retrieve/user_register/userprofile/register/check_collision/userprofile/checkcollision/refresh_captcha/userprofile/refresh_captcha/get_email_captcha/userprofile/get_email_captcha/get_review_queue/api/video/review_queueget_video_info_bulk/api/video/infobulkget_video_detail_bulk/api/video/detailbulkget_software/video/get_software/video_preview/video/preview/video_download/video/download/video_query/video/query/video_query_by_id/video/query_by_id/newest_queue/video/newest_queue/freeze_queue/video/freeze_queue/captcha_dbCaptchaStoretask_dbDBTaskResultaccountlinkqueue_dbAccountLinkQueueplatform accountsaccountlinkplatform_dbAccountSaoleiAccountMinesweeperGamesAccountBilibiliAccountWorldOfMinesweeperAccountQQvideosaolei_dbVideoSaoleicustom_pluck_dbCustomPluckRecordidentifier_dbIdentifieruserms_dbUserMStournament_dbTournamentGSCTournamentWeeklyTournamentparticipant_dbTournamentParticipantGSCParticipantWeeklyParticipanttournament_user_dbTournamentUseruserprofile_dbUserProfileemail_otp_dbEmailVerifyRecordvideo_dbVideoModelExpandVideoModeltask_summary_cacheapi:monitor/tasksummarydisk_usage_cacheapi:monitor/diskusagevideo_summary_cacheapi:monitor/videosummarymemory_usage_cacheapi:monitor/memoryusageTTL 300spluck_rank_cachecustomranking:pluck:{level}:rankzsetpluck_detail_cachecustomranking:pluck:{level}:detailhashnewest_cachenewest_queuehashfreeze_cachefreeze_queuehashreview_cachereview_queuehashtournament_cachetournament:normalhashsubclass + dataparticipant_cachetournament:normal:participantshashtournament_user_rank_cachetournament:user:{field}zsetmember = user_idtournament_user_score_time_cachetournament:user:score_current:last_updatedstring年度锚点:1 月 1 日 UTCmonitor_summary_cacheapi:monitor/*TTL 300svideo_filesvideo filesavatar_filesavatar filescapture_video_updatecapture_video_updaterefresh_state_queue_on_video_saverefresh_state_queue_on_video_saveupdate_video_count_on_video_saveupdate_video_count_on_video_saveupdate_video_count_limit_on_video_saveupdate_video_count_limit_on_video_saveupdate_video_count_on_video_deleteupdate_video_count_on_video_deleterefresh_custom_pluck_rank_on_video_saverefresh_custom_pluck_rank_on_video_saveupdate_custom_pluck_cache_on_record_saveupdate_custom_pluck_cache_on_record_saveupdate_custom_pluck_cache_on_record_deleteupdate_custom_pluck_cache_on_record_deletecheckin_video_before_createcheckin_video_before_createadd_created_video_to_checked_tournamentsadd_created_video_to_checked_tournamentsupdate_cache_on_tournament_deleteupdate_cache_on_tournament_deleteupdate_cache_on_tournament_saveupdate_cache_on_tournament_saveupdate_cache_on_participant_saveupdate_cache_on_participant_saveupdate_best_score_on_gsc_participant_saveupdate_best_score_on_gsc_participant_saveupdate_best_score_on_weekly_participant_saveupdate_best_score_on_weekly_participant_saveupdate_best_score_on_gsc_participant_deleteupdate_best_score_on_gsc_participant_deleteupdate_best_score_on_weekly_participant_deleteupdate_best_score_on_weekly_participant_deleteremove_participant_cache_on_deleteremove_participant_cache_on_deletetask_saolei_video_import_bulktask_saolei_video_import_bulktask_saolei_video_importtask_saolei_video_importtask_gsc_finishtask_gsc_finishtask_gsc_refresh_besttask_gsc_refresh_besttask_award_tournamenttask_award_tournamenttask_weekly_finishtask_weekly_finishtask_weekly_refresh_besttask_weekly_refresh_bestrefresh_tournament_score_referenceAPSchedulerrefresh_tournament_score_referencerebuild_tournament_current_score_cachemanage.pyrebuild_tournament_current_score_cache

缓存数据结构 ​

所属 appkeyRedis 类型数据结构
videomanagernewest_queuehashfield = video_id;value = VideoQueue JSON,包含 state、tournament、software、time、player_id、identifier、level、mode、timems、bv、cl、ce、right_ce。
videomanagerfreeze_queuehash同 newest_queue,用于冻结录像队列。
videomanagerreview_queuehash同 newest_queue,用于待审核录像队列。
effrankingeffranking:thrp:recordshashfield = player_id;完整 b/i/e 原始纪录 JSON,每项为 null 或包含 value、video_id、upload_time 的对象。sum 不重复存储。
effrankingeffranking:thrp:{stat}zsetstat = b/i/e/sum;member = player_id,score 为六位小数成绩和分钟级达成时间的排序编码,升序读取,不用于恢复成绩。
customrankingcustomranking:pluck:{level}:rankzsetmember = player_id;score = pluck,当 pluck == 0 时使用 timems - MAX_TIMEMS 降低 0 碰撞风险。
customrankingcustomranking:pluck:{level}:detailhashfield = player_id;value = detail JSON,包含 video_id、mode、timems、bv、upload_time。
tournamenttournament:normalhashfield = tournament_id;value = CachedTournament JSON,包含 id、state、subclass、host_id、start_time、end_time、data。data 保存子类独占字段:GSC 为 order、token;周赛为 year、week、tournament_format。
tournamenttournament:normal:participantshashfield = user_id;value = list[CachedNormalParticipant] JSON,每项包含 id、token、arbiter_identifier、tournament、start_time、end_time。
tournamenttournament:user:score_currentzsetmember = user_id;score = score_current × tournament_score_decay_factor(last_updated, 缓存时间基准);所有成员使用同一时间基准。数据库 score_current = 0 时不写入。
tournamenttournament:user:score_current:last_updatedstring带时区的 ISO datetime;当前积分 zset 的年度统一锚点,正常为当年 1 月 1 日 00:00 UTC。由年度 APScheduler 任务更新;普通积分发放不推进。调度任务延迟时继续统一使用旧锚点。
tournamenttournament:user:score_total / gsc_total / gsc_best / weekly_total / weekly_classic_total / weekly_classic_bestzsetmember = user_id;score = TournamentUser 对应字段值。各 total 字段为 0 时不写入;gsc_best、weekly_classic_best 为 MAX_TOURNAMENT_BEST 时不写入。
monitorapi:monitor/videosummaryDjango cachevideo_summary 返回体,TTL 300 秒。
monitorapi:monitor/tasksummaryDjango cachetask_summary 返回体,TTL 300 秒;管理员删除或重启任务后失效。
monitorapi:monitor/diskusageDjango cachedisk_usage 返回体,TTL 300 秒。
monitorapi:monitor/memoryusageDjango cache进程和 Redis 两块内存统计的完整返回体,TTL 300 秒;独立不可用结果也缓存,命中不续期。
articlearticleslist文章目录项字符串,来自 assets/article 或静态目录下的文章文件。

TournamentUser 是比赛积分的持久化汇总表;Redis 中另用 7 个 sorted set 保存排行榜入口。站内用户创建 TournamentParticipant / GSCParticipant / WeeklyParticipant 时,保存信号会在当前数据库事务内立即创建缺失的 TournamentUser;删除 participant 不会跟随删除 TournamentUser。无站内用户的 participant 在数据库中保留 user_id = NULL,但 API 序列化时统一输出 user_id = 0,前端只按 0 识别非站内用户。GSC / 周赛 finish 任务先调用 ensure_tournament_users,为本场所有站内参赛用户补建缺失的默认 TournamentUser,然后才调用 delete_participants_without_videos 删除无录像站内 participant。排名积分发放和 best 刷新是独立的非关键后台任务,入口同样先执行 ensure_tournament_users,支持独立执行或重跑;随后各自从本场剩余站内 participant 出发,通过 participant.user.tournamentuser 取得对应的 TournamentUser,并使用 select_related('user__tournamentuser') 避免 N+1。积分发放任务读取并衰减既有 TournamentUser.score_current,再根据本场 participant 的 rank_score 增量写回 TournamentUser 和 TournamentParticipant.rank_score,随后同步刷新 score_current、score_total 和对应分类 total 的 zset。历史最好成绩在 participant 保存后只读取当前 participant 和对应比赛子表,并与 TournamentUser.gsc_best / weekly_classic_best 直接比较;只有当前成绩更好时才改变内存值。结算流程使用 bulk_update 写入 rank_score,不会触发保存信号,因此 best 刷新通过 refresh_gsc_best_scores / refresh_weekly_best_scores 作为独立后台任务执行,并在写库后刷新对应 best zset;best 与排名积分发放没有顺序依赖。为了简化结算代码,积分发放和 best 刷新都不筛选字段是否发生变化,会统一 bulk_update 候选 participant 和对应 TournamentUser。结算链路通过 tournament logger 写入 logs/tournament.log,记录后台任务、删除无录像 participant、读取 TournamentUser、成绩/排名刷新、积分发放、best 刷新、状态切换和录像公开等阶段的处理数量。没有有效历史成绩时,best 字段使用 MAX_TOURNAMENT_BEST 作为哨兵值,并且不写入 Redis。participant 删除时,GSC / 周赛各自的信号会在当前事务内按需调用 calculate_gsc_best_score / calculate_weekly_classic_best 重算该类型历史最好成绩,并同步更新对应 best zset。由于 TournamentUser 是数据库汇总数据,participant 信号触发的创建和 best 更新必须在当前事务内立即执行,不使用 transaction.on_commit。如果需要修复历史汇总数据,尤其是把旧的 0 best 值迁移到新的最大值哨兵,可以运行 manage.py refresh_tournament_user_stats。该命令会先调用 tournament.services.refresh_tournament_user_total_fields 重建 score_total、gsc_total、weekly_total 和 weekly_classic_total,再执行命令内的 best 重建步骤写回 gsc_best 和 weekly_classic_best;score_current 依赖实时衰减,不由该命令刷新。如果 Redis 排行缓存丢失或需要按当前数据库状态重建,可以运行 manage.py rebuild_tournament_user_cache。

当前积分 zset 使用固定年度锚点。update_tournament_users 读取缓存锚点,仅换算本批用户,不再根据用户 last_updated 推进基准或整体衰减其他成员。空缓存首次写入时初始化为当年 1 月 1 日 00:00 UTC。折算使用 tournament_score_decay_factor(last_updated, 锚点),负时间差通过负指数自动兼容;因此年内新积分折算到年初时会放大,但所有成员共用锚点,排序等价于实时积分。锚点读取和本批写入使用 redis-py transaction(WATCH / MULTI / EXEC),年度更新并发发生时重试。数据库仍保留用户各自的 score_current / last_updated,API 回表输出这些原始值,前端按 globalNow 衰减显示;统一锚点只影响 Redis 排序。更新其他 total / best 字段不会改变当前积分基准。

common.apscheduler.refresh_tournament_score_reference 在每年 1 月 1 日 00:00 UTC 调用 TournamentCache.refresh_tournament_score_reference,使用 ZUNIONSTORE 权重将当前积分 zset 整体折算到新锚点,并在同一 Redis 事务中设置锚点;其他排行和数据库不变。同一年重复执行无副作用。调度器启动时也执行一次,补齐跨年停机;尚未补齐时,结算仍沿用旧锚点,不会混用年份。读取旧锚点、整体折算及设置新锚点采用 WATCH / MULTI / EXEC,与结算写入并发时保持一致。

rebuild_tournament_current_score_cache 从数据库分批读取当前积分,按当年年初锚点重算并原子替换当前积分 zset 和锚点,不改其他 6 个排行或数据库;并发缓存写入会触发重试,读请求在提交前仍能读取旧排行。为避免数据库尚未提交但缓存已写入的跨系统窗口,重算期间仍应暂停积分结算和历史积分修正任务。部署年度锚点方案后应先运行此命令,再重启 APScheduler。rebuild_tournament_user_cache 则清理并分批重建全部 7 个 zset 和年初锚点,重建期间仍需暂停其他排行写入。清理全部排行时也删除锚点 key;非空当前积分 zset 缺少锚点时会报错,要求显式重建,不进行数据库 fallback。

每批排行缓存更新按字段汇总:每个 zset 最多执行一次多成员 ZADD 和一次多成员 ZREM,分别写入非默认分数与移除默认分数成员,不再为每个用户单独排入命令。缓存重建按 batch_size 分批读取。

ensure_tournament_users 按本场 participant 的非空 user_id 去重并执行 get_or_create,不覆盖已有记录;默认积分为 0,best 为 MAX_TOURNAMENT_BEST,因此补建本身不写入排行 zset。此步骤兼容早期只有 participant、尚无 TournamentUser 且未发放积分的历史数据,不负责恢复已丢失的历史积分。新 participant 仍由创建信号保证关联完整;删除信号不容忍缺失关联,也不补建记录。每次任务会记录补建数量,无需额外管理命令。

GSCParticipant.t37 是数据库持久化 generated field,并建立 gsc_t37_idx 索引,服务于 GSC 排名和历史最好成绩查询。保存信号使用当前 participant 实例上的临时 t37 值进行 best 增量比较,因此不会为了读取 generated field 再查询一次 participant。

写入与重建入口 ​

缓存主要写入入口重建 / 清理入口
录像状态队列videomanager.signals.refresh_state_queue_on_video_savevideomanager.cache.add_videos_to_state_queues_bulk 可按状态批量恢复普通队列。
效率 Thrp 排行effranking.signals 与批量 services,提交后更新rebuild_eff_ranks 全量重建;管理员 /api/effranking/thrp/admin/rebuild_record 修复单项,sum 仅从个人 hash 重算。
自定义 pluck 排行customranking.services.update_custom_pluck_top_cachemanage.py rebuild_custom_pluck_cache 从 CustomPluckRecord 全量重建。
NORMAL 比赛TournamentCache.update_tournamentmanage.py rebuild_tournament_cache 显式查询 NORMAL GSC 与周赛并重建。
NORMAL 参赛关系TournamentCache.update_participant / remove_participantmanage.py rebuild_tournament_cache 按 user_id 分组重建。
比赛积分排行TournamentCache.update_tournament_user / update_tournament_users;APScheduler 年度锚点更新manage.py rebuild_tournament_user_cache 重建全部 7 个 zset;manage.py rebuild_tournament_current_score_cache 原子重算当前积分 zset 和年度锚点。
common 摘要对应 API 内部 cache.setTTL 到期自动失效。
文章目录article.views.update_list管理员手动调用 update_list 全量刷新。

读取约定 ​

  • NORMAL 比赛列表只读 tournament:normal,不在缓存未命中时回落数据库;缓存与数据库不同步视为写路径 bug。
  • 录像队列缓存不保存比赛录像,VideoQueueCache.add / add_bulk 会跳过 ongoing_tournament=True 的录像。
  • 参赛 checkin 先读 tournament:normal:participants,命中后再按 tournament id 查询数据库对象,用于写入录像的多对多关系。
  • customranking:pluck:{level}:rank 只保存排序所需数据,展示字段来自同级 detail hash。