本文由 FlintHub 开发文档归档发布。原始文档日期见标题前缀,来源:暂存20260913/docs/队列调度模式改造执行计划 (2).md。
SoSite 1.0 — 异步任务队列调度模式后台开关 改造执行计划
文档状态:待确认(2026-08-13)
目标版本:SoSite 1.0(SplitDB 纯 SQLite 分片引擎)
背景:已有完整任务队列(
Queue/QueueConsumer/cli/worker.php),但业务侧(发帖/回帖)无条件入队,不适应"虚拟主机无 SSH"环境。本计划新增可配置的「队列任务处理模式」开关,覆盖三种部署形态。
一、需求评估结论
1.1 现状盘点(已读代码确认)
| 位置 | 现状 | 结论 |
|---|---|---|
app/Models/Thread.php::insert() (L95-96) | 无条件 Queue::push('rebuild_search', ['topic_id'=>$id]) | 需按模式分支 |
app/Models/Post.php::insert() (L85-86) | 无条件 Queue::push('stats', [...]) | 需按模式分支 |
app/SplitDB/Queue.php::push() | 随机分发 3 队列文件,返回任务 ID | 无需改动,复用 |
app/Helpers/Search.php::indexThread($id) | 同步重建单帖倒排索引(读分片 extern) | 可直接同步调用(sync 模式) |
app/Helpers/Settings.php::runtimeBuild() | 重建 4 项统计并写 settings 表 _runtime_* | 可直接同步调用(sync 模式) |
app/Helpers/Settings.php::get($key,$default) | 三层缓存读 KV(内存→文件→DB) | 读取 queue_mode 用 |
cli/worker.php | 常驻/--once 消费,handler 已挂接 rebuild_search/stats | 模式 C 依赖,无需改动 |
cron_trigger.php | 不存在 | 需新建(模式 B 入口) |
后台设置页 SettingsController::basic + admin/settings_basic.php | 基本信息表单,setValue 逐键保存 | 在此页新增下拉框 |
1.2 关键设计确认
- 存储:
settings表键queue_mode,值sync/cron/cli,默认sync。
- 新装:
Schema::seedDefaults()补默认值(幂等)。 - 老库:
Settings::get('queue_mode', 'sync')兜底,无需迁移脚本。
- 同步直写语义(模式 A):
- 发帖:
Search::indexThread($id)(实时索引)+Settings::runtimeBuild()(实时统计)——与 worker handler 完全同构,数据 100% 实时。 - 回帖:
Settings::runtimeBuild()(实时统计)。
- 入队语义(模式 B/C):保持现状
Queue::push,立即返回。 - cron_trigger.php 安全设计:
- 仅当
queue_mode === 'cron'时执行(防止 cli 模式下误触发双消费); lock/目录文件锁防并发重复消费;- 有界消费全部 3 个队列(复用 worker handler 逻辑,
drain后退出)。
二、改造执行计划表(严格串行,每步自测)
| # | 任务 | 交付物 | 验证方式 |
|---|---|---|---|
| S1 | app/Models/Thread.php::insert() 按 queue_mode 分支:sync → Search::indexThread($id) + Settings::runtimeBuild();cron/cli → 保留 Queue::push | 代码修改 | CLI 冒烟:三种模式发帖后搜索/统计即时性或队列任务数符合预期 |
| S2 | app/Models/Post.php::insert() 按 queue_mode 分支:sync → Settings::runtimeBuild();cron/cli → 保留 Queue::push('stats') | 代码修改 | CLI 冒烟:sync 回帖后 total_posts 实时 +1 |
| S3 | app/SplitDB/Schema.php::seedDefaults() 增加默认 queue_mode=sync(幂等) | 代码修改 | 空库 bootstrap 后 settings 表含 queue_mode=sync |
| S4 | 后台设置页:SettingsController::basic 增加 queue_mode 保存键;admin/settings_basic.php 新增「队列任务调度模式」区块(下拉框 + 三种模式说明 + 模式 B/C 配置指引,Alpine 联动显隐) | 视图 + 控制器 | 后台保存后 settings 表值更新,刷新页面回显正确 |
| S5 | 新建 cron_trigger.php(web 入口:cron 模式守卫 + 文件锁 + 三队列有界消费) | 新文件 | 置 cron 模式→访问 URL→队列任务被消费置 done;非 cron 模式拒绝 |
| S6 | 同步 update/ 镜像(S1-S5 全部改动文件)+ 更新 CHANGELOG.md | 交付 | 与根目录 diff 一致;php -l 全过 |
说明:
cli/worker.php、Queue.php、QueueConsumer.php无需改动(模式 B/C 复用现有消费链路)。
三、详细设计
3.1 业务接入(S1 / S2)
在 Thread::insert() 步骤 5、Post::insert() 步骤 6 处,读取模式并分支:
// Thread::insert 步骤 5(原为无条件入队)
$mode = \app\Helpers\Settings::get('queue_mode', 'sync');
if ($mode === 'sync') {
// 模式 A:同步直写(实时索引 + 实时统计)
\app\Helpers\Search::indexThread($id);
\app\Helpers\Settings::runtimeBuild();
} else {
// 模式 B/C:入队,立即返回
Queue::push('rebuild_search', ['topic_id' => $id]);
}// Post::insert 步骤 6(原为无条件入队)
$mode = \app\Helpers\Settings::get('queue_mode', 'sync');
if ($mode === 'sync') {
// 模式 A:同步刷新全站统计
\app\Helpers\Settings::runtimeBuild();
} else {
\app\SplitDB\Queue::push('stats', ['type' => 'reply', 'thread_id' => $threadId, 'user_id' => ...]);
}语义对齐:sync 直写执行的函数与
cli/worker.php中同名 handler 完全一致,保证三种模式下最终数据一致。
3.2 配置存储(S3)
Schema::seedDefaults() 的默认 settings 数组追加:
'queue_mode' => 'sync', // sync=同步直写 / cron=Cron 定时触发 / cli=CLI 常驻消费(setValue 走 ON CONFLICT DO UPDATE,幂等;老库靠 get(..., 'sync') 兜底,无需迁移。)
3.3 后台 UI(S4)——布局预览
在 admin/settings_basic.php 新增「队列任务调度」区块(置于"功能开关"之后):
┌─ 队列任务调度模式 ─────────────────────────────────────────┐
│ 队列任务处理模式 [ 同步直写 (默认) ▾ ] │
│ │
│ ● 同步直写:无需额外配置,数据实时,适合小型社区 │
│ ○ Cron 定时触发:适合虚拟主机(无 SSH) │
│ ○ CLI 常驻消费:适合 Linux VPS(Supervisor) │
│ │
│ [模式 B 选中时显示] 请在虚拟主机控制面板添加 Cron 任务: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ wget -q -O /dev/null http://你的域名/cron_trigger.php │ │
│ └─────────────────────────────────────────────────────┘ │
│ [模式 C 选中时显示] 请确保服务器已安装 Supervisor 并 │
│ 配置运行 cli/worker.php │
└───────────────────────────────────────────────────────────┘- 表单:
<select name="queue_mode">三项(sync/cron/cli); - 联动提示:利用后台已加载的 Alpine(sostate.js),
x-data="{qm:'...'}"+x-show按选中项显示对应指引; - 保存:
SettingsController::basic的$keys数组加入'queue_mode';保存后Settings::buildCache()已存在,自动生效。
3.4 cron_trigger.php(S5)设计
1) 加载框架(Autoloader)
2) 守卫:Settings::get('queue_mode') !== 'cron' → 输出提示并退出(防 cli 模式双消费)
3) 文件锁:lock/cron_trigger.lock(LOCK_EX|LOCK_NB),拿不到锁说明上次未结束,直接退出
4) 复用 worker 的 handler(rebuild_search / stats),对 3 个队列各 drain() 一次(有界)
5) 释放锁,输出处理统计,退出安全说明:cron 模式是"公开可触发但只做队列消费",无写权限放大风险;锁防并发重入;模式守卫防误配。
四、交付清单
| 文件 | 操作 |
|---|---|
app/Models/Thread.php | ✏️ 改(insert 步骤 5 分支) |
app/Models/Post.php | ✏️ 改(insert 步骤 6 分支) |
app/SplitDB/Schema.php | ✏️ 改(seedDefaults 加 queue_mode 默认值) |
app/Controllers/Admin/SettingsController.php | ✏️ 改(basic 保存键加 queue_mode) |
app/Views/admin/settings_basic.php | ✏️ 改(新增调度模式下拉区块) |
cron_trigger.php | 🆕 新建(web 触发入口) |
update/ 全量同步 + CHANGELOG.md 追加 | 📦 交付 |
五、验收流程(用户侧)
- 后台 → 基本信息 → 选择「同步直写」保存 → 发帖 → 立即搜索可见、统计即时变化;
- 改选「Cron 定时触发」保存 → 页面显示 wget 指引 → 发帖 → 搜索暂无新帖 → 浏览器访问
cron_trigger.php→ 搜索命中、队列清空; - 改选「CLI 常驻消费」保存 → 显示 Supervisor 指引 →
php cli/worker.php消费验证; - 重复执行 cron_trigger.php 不产生重复消费(锁生效)。
六、备注
- 博客/分类等其余业务(BlogController 等)已是同步写入(
Search::indexBlog直调),不涉及队列,无需改动。 cli/worker.php的--once模式已可被 cron 直接调用,本计划新增cron_trigger.php仅为 Web 入口(虚拟主机无法执行 PHP CLI 时使用)。- 全部改动文件
UTF-8 without BOM + LF,php -l校验。