# ============================================================ # 题王 QKing · 配置文件(config.ini) # 本文件是程序唯一的配置文件:端口、更新源、版权等都在这里改。 # 修改后重启程序(或双击「一键关闭服务.bat」后重开)即可生效,无需重新打包。 # 编码:UTF-8(记事本打开即可编辑)。 # ============================================================ [app] # 站点名称(页脚等展示) name = 题王 # 版权文案(页脚展示) copyright = 题王 QKing · 作者 sakaay 版权所有 # 服务监听地址:0.0.0.0 表示接受局域网内所有机器访问 host = 0.0.0.0 # 服务端口(默认 8000;被占用时改这里,例如 8010) port = 8000 # 页脚展示的版本号。真实版本号随包内置(build_defaults.json),自动升级比对以它为准; # 这里填了只影响页脚显示,留空 = 自动显示真实版本号。 version = # 是否部署在反向代理(CDN / EdgeOne / Nginx)之后:1 = 采信 X-Forwarded-*, # 使 https 识别与客户端真实 IP 正确;0(默认)= 不采信。 # 仅当确实位于反代之后才改为 1,否则他人可伪造 X-Forwarded-For 冒充来源 IP。 # 环境变量 BEHIND_PROXY=1 亦可开启(优先级高于本项)。 behind_proxy = 0 # behind_proxy=1 时,受信的反代地址列表(逗号或空格分隔,如 10.0.0.8)。 # 留空表示信任任意来源的 X-Forwarded-*,该头可被伪造,建议收敛为反代真实 IP。 proxy_trusted_hosts = [database] # 数据库文件路径(相对**数据目录**:源码运行=项目根,打包运行=exe 所在目录)。 # 默认 data/quiz.db —— 库文件与备份统一放在 data/ 下;改成绝对路径则原样使用。 path = data/quiz.db # 数据库自动备份保留天数(0 表示不自动清理) backup_keep_days = 30 [update] # 版本清单(latest.json) 地址。换服务器改这里即可,无需重新打包。 # 安全口径:默认只接受 https;清单与更新包都必须带 MD5,缺 MD5 一律拒绝下载/安装。 manifest_url = https://dd.sakaay.com/files/latest.json # 是否允许明文 http(含 HTTPS 证书校验失败时回落明文 http):默认 0 = 不允许。 # 改为 1 等于放弃升级链路的传输保护,仅在自有内网源确实拿不到可信证书时才开。 allow_insecure_http = 0 # 更新源 host 白名单(逗号或空格分隔,如:dd.sakaay.com)。留空 = 不限制。 manifest_hosts = [log] # 日志级别:DEBUG / INFO / WARNING / ERROR(默认 INFO,改完重启程序生效) # 排查问题时改成 DEBUG —— 会记录每个请求的进出与请求头,最详细,但日志体积增长很快; # 查完请改回 INFO,避免单份日志很快被写满轮转。 level = INFO # 日志文件切分方式(日志统一写在程序同目录的 log/ 文件夹里,不存在会自动创建): # daily(默认)= 按日期一个文件:log/运行日志_2026-09-25.log,同一天多次运行追加写, # 每次运行开头有一段「本次运行开始」横幅分隔,既不覆盖也不分散; # session = 每次运行一个独立文件:log/运行日志_2026-09-25_143512.log。 # 注意:判分子进程等也会各写一个文件,排障时才建议临时改它。 file_mode = daily # 历史日志保留天数(0 = 永不清理):超过天数的 log/运行日志* 会在启动时自动删除。 keep_days = 30 [perf] # ============================================================ # 实时作答的写路径性能开关(**改完必须重启程序**,这些值只在启动时读一次) # 也可以用升级页「性能开关」卡片改;本节的注释与顺序在保存时会原样保留。 # 读取优先级:环境变量(QUIZ_*) > 本节 > 内置默认。 # 不确定要不要开时:**保持默认**。默认形态(不拆 + 逐笔提交)最稳、 # 数据全在一个库里,现场排查最简单。开之前先看 分库分表与组提交.md。 # ============================================================ # 实时作答分片数:1 = 不拆(默认,推荐)。 # 【改它 ≠ 改开关,是改数据布局】改成 4 之后已有作答还留在原处,必须停服执行: # python -m core.answerstore --audit (只读体检) # python -m core.answerstore --migrate --commit (自动备份 + 迁移 + 自动校验) # python -m core.answerstore --drop-main --commit (确认无误后关掉回退窗口) # 不迁移就起服 → 一部分作答读不到(启动日志会报 ERROR 提醒)。 # 升级页的「系统运行状态」卡片会显示当前分片数与迁移状态,并给出一键复制命令。 shards = 1 # 组提交(写队列):1 = 开(默认关)。把并发到达的多笔作答合并成一次事务提交。 # 与分片正交;实测两者**一起开**才有意义(单独开任一都更慢,见文档)。 write_batch = 0 # 一批最多合并多少笔(只在 write_batch=1 时有效)。**默认 8 是实测最优,别调大**: # 4→2052 笔/s | 8→2004 | 16→1838 | 32→1682 | 200→1478(越大越慢)。 # 升级页里这一项是只读展示(避免误调成 200 把现场拖慢)。 batch_max = 8 # 凑批最长等待(毫秒):当前批没凑满时最多再等这么久就提交。 batch_wait_ms = 5 # 同步端点的线程池令牌数(0 = 用框架默认的 40 个线程)。 # 本程序绝大多数接口是同步函数,全部排这个池执行;机器核多、并发高时可上调 # (例如按 CPU 核数 × 4~8 试,别一次给到几百)。升级页可改,改完重启生效。 threadpool = 0 # 启动期自动把**数据布局**收敛到本节开关要求的形态(1 = 允许,默认;0 = 关掉)。 # 为什么需要它:分片开关与数据位置必须一致,否则会出现"作答看起来不见了"—— # 开关说 4、作答却还在主库(旧版本刚升上来)→ 分片形态下一条都读不到; # 开关说 1、作答却只在分片里(之前开过又关掉)→ 未分片形态只读主库,同样读不到。 # 程序在**对外服务之前**自己判断并收敛:先自动备份,再迁移/合回,然后校验; # 校验不通过就弹窗提示并拒绝起服务(宁可当场停下,也不要让人看到少了一半的作答)。 # 注意:它**不会**自动清主库副本(--drop-main 那种不可逆收尾永远留给人来点)。 # 排障时可临时设成 0 关掉自动收敛,改用升级页「系统运行状态」里的命令手工处理。 auto_layout = 1 # 业务分库(域):题库+组卷搬进 quiz.qb.db、整卷考试+成绩搬进 quiz.exam.db。 # 写上 "qb,exam" = 只启用点名的这两个域;写 0 = 强制不挂(回到未拆分形态); # **留空 = 自动** —— 只要域文件存在且带迁移标记就启用,所以拆完不需要再回来改配置。 # 拆: --domains --apply(或 python -m core.domains --apply,会自动先备份)。 # 注意:还没拆的时候这一项写了也没用(表还在主库,应用照旧读写主库,形态与改造前一致)。 domains = # 学生端「自动测试」的轮询间隔(毫秒):**默认 0 = 完全关闭**。 # 自动测试(学生端自动登录 / 自动作答)只在开发或内部测试时才用得上。开着它时, # 每一个打开的学生端页面都会按这个间隔定时请求服务端 —— 一个班几十台设备就会被 # 放大成持续压力,而常态上课根本用不到。所以默认关着。 # 要用就填一个明确的毫秒数(如 3000 = 3 秒),测完改回 0 即可。 # **改完立即生效,不用重启**:在升级页「性能开关」里保存、或者用记事本直接改本文件 # 都算(本项每次都读盘),改完刷新一下页面即可。 auto_poll_ms = 0