[开发]SoSite 1.0 — 任务调度独立模块改造计划

👑Lv.11 元老 🌞 骨干会员
2026-10-24 00:13:25

本文由 FlintHub 开发文档归档发布。原始文档日期见标题前缀,来源:暂存20260913/docs/任务调度独立模块改造计划 (2).md。

SoSite 1.0 — 任务调度独立模块改造计划

文档状态:待确认(2026-08-13)

目标:将「队列任务调度」从「基本信息」设置中提取为独立后台模块,与「搜索设置」并列

现状基线:P8 已完成 queue_mode(sync/cron/cli)业务分支 + cron_trigger.php;本次仅做界面/导航/交互重构,业务逻辑复用


一、需求评估与现状勘察(已读代码确认)

勘察项现状结论
侧边栏导航app/Views/admin/_sidebar.php L14:「搜索设置」是「站点设置」组最后一项在其后新增「任务调度」菜单项
路由注册index.php L116-125:`/admin/settings/basicdisplay
设置保存SettingsController::basic() L23-27 $keys 含 queue_mode;settings_basic.php L90+ 已有「队列任务调度」区块移除 basic 页区块与保存键,迁至独立页
队列统计Queue::countByStatus(int $queueIndex) 返回单队列 {status: count};Queue::QUEUE_COUNT = 3面板需聚合 3 队列(pending+processing / done / failed)
图标体系TemplateCompiler::icon($name) 内置映射:'sync'/'refresh' = 、'clock'/'time' = 、'settings' = 菜单图标用 sync(🔄)或 clock(⏳),无需新增图标资源
手动触发现仅有 cron_trigger.php(web 入口)与 cli/worker.php(CLI)建议新增页面内「立即处理」按钮(见三.4)


二、改造执行计划表(待用户确认后串行实施)

#任务交付物验证方式
T1index.php 注册路由:GET/POST /admin/settings/queue → AdminSettingsController::queueSettings路由访问 URL 200 且渲染新页
T2SettingsController:新增 queueSettings()(保存 queue_mode + 手动触发 action + 聚合队列统计);basic() 的 $keys 移除 queue_mode控制器POST 保存后 settings 表更新;basic 页不再保存该项
T3app/Views/admin/queue_settings.php:独立页面(标题区 / 三模式卡片 / 队列面板 / 防呆弹窗 / 手动触发按钮)视图页面结构与文案按需求逐条核对
T4settings_basic.php:删除「队列任务调度」区块(迁走);_sidebar.php:搜索设置下方新增「任务调度」菜单项视图导航出现新项、basic 页无残留区块
T5同步 update/ 镜像 + 更新 CHANGELOG.md交付fc 比对一致;php -l 全过


三、详细设计

3.1 路由(T1)— index.php

在 L125 /settings/search 后追加:

$r->get('/settings/queue', [AdminSettingsController::class, 'queueSettings']);
$r->post('/settings/queue', [AdminSettingsController::class, 'queueSettings']);

3.2 控制器(T2)— SettingsController::queueSettings()

参照 searchSettings() 模式:

public function queueSettings()
{
    $settingModel = new \app\Models\Setting();

    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        Csrf::verifyOrDie($_POST['csrf'] ?? '');
        $action = $_POST['action'] ?? '';

        // 保存模式
        if ($action === 'save_mode') {
            $mode = $_POST['queue_mode'] ?? 'sync';
            if (!in_array($mode, ['sync', 'cron', 'cli'], true)) $mode = 'sync';
            $settingModel->setValue('queue_mode', $mode);
            Settings::buildCache();
            \app\Helpers\AuditLog::log('admin_action', 'setting', 0, "设置队列调度模式: {$mode}");
            $this->redirect('/admin/settings/queue?success=1');
        }

        // 立即处理(手动触发,见 3.4)
        if ($action === 'flush') {
            $processed = $this->flushQueueNow();
            $this->redirect('/admin/settings/queue?msg=flushed_' . $processed);
        }
    }

    $msg = $_GET['success'] ?? '' ? '设置已保存' : '';
    if (strpos($_GET['msg'] ?? '', 'flushed_') === 0) {
        $msg = '✅ 已立即处理 ' . (int)substr($_GET['msg'], 8) . ' 个待处理任务';
    }

    $allSettings = $settingModel->getAll();
    $this->view('admin/queue_settings', [
        'settings' => $allSettings,
        'queue_stats' => $this->queueStatsAggregate(),   // 聚合三队列
        'msg' => $msg,
        'error' => $_GET['error'] ?? '',
        '__nav_active' => 'settings_queue',
    ]);
}

聚合统计(面板数据源):遍历 3 队列 Queue::countByStatus($i) 汇总:

private function queueStatsAggregate(): array
{
    $pending = 0; $done = 0; $failed = 0;
    for ($i = 0; $i < Queue::QUEUE_COUNT; $i++) {
        $map = Queue::countByStatus($i);
        $pending += (int)($map['pending'] ?? 0) + (int)($map['processing'] ?? 0);
        $done   += (int)($map['done'] ?? 0);
        $failed += (int)($map['failed'] ?? 0);
    }
    return ['pending' => $pending, 'done' => $done, 'failed' => $failed];
}

3.3 视图(T3)— app/Views/admin/queue_settings.php

按需求文案逐条渲染(标题区 / 三模式卡片 / 队列面板 / 防呆弹窗 / 手动触发),文案严格采用需求原文:

┌─ 任务调度引擎 ─────────────────────────────────────────────┐
│  控制发帖、回帖、搜索重建等后台任务的执行方式。选择最适合您    │
│  服务器环境的模式,以平衡"实时性"与"服务器性能"。             │
│                                                            │
│  (模式选择:单选卡片 / 下拉)                                 │
│  ○ 模式一【同步直写】(推荐)                               │
│      适用场景:仅需 PHP 环境,无需额外配置,适合个人测试或    │
│                廉价虚拟主机。                               │
│      行为特征:发帖/回帖成功后,页面等待搜索索引更新完毕后    │
│                返回结果。数据 100% 实时,用户体验极致无延迟。 │
│      技术代价:在极高并发下,可能会轻微增加页面响应时间。     │
│  ○ 模式二【Cron 定时触发】                                  │
│      适用场景:拥有服务器 Crontab 权限,但无法常驻 PHP 进程   │
│                的环境。                                     │
│      行为特征:发帖后任务入队(入 SQLite),由您设置的定时     │
│                任务(如每分钟触发一次)批量处理索引更新。系统  │
│                会在后台默认保留 1 分钟的"最终一致性"窗口。    │
│      配置指引:[提示框] * * * * * php /网站根目录/cli/worker.php │
│                --once >> /dev/null 2>&1                     │
│  ○ 模式三【CLI 常驻消费】                                   │
│      适用场景:拥有 Linux VPS 或独立服务器,支持长期后台进程   │
│                (依赖 Supervisor)。                        │
│      行为特征:极致的异步处理。发帖后任务秒入队列,由后台持续   │
│                运行的 worker.php 进程实时消费。页面响应速度    │
│                最快。                                       │
│      配置指引:此模式需要安装 supervisor,并启动 php          │
│                cli/worker.php 进程。                        │
│                                                            │
│  ─────────── 队列面板 ───────────                           │
│  ⏳ 待处理任务:N 个 | ✅ 已完成任务:M 个 | 📦 当前模式:XXX │
│  [立即处理待处理任务]  [保存配置]                            │
└─────────────────────────────────────────────────────────────┘

技术要点:

  • 模式选择:需求要求"留空/下拉选框形式",采用与 basic 页一致的 <select name="queue_mode"> + Alpine x-model 联动(复用 nginx-snippet/maintenance-box 等既有样式类,保持一致观感)
  • 防呆弹窗:<form x-on:submit="if(!confirm('切换至异步模式后,原已产生的旧任务将由新模式接管,不会丢失。')) return false"> ——仅当从 sync 切到 cron/cli 时提示(可用 Alpine 判断当前值 + 新值)
  • 队列面板:queue_stats 聚合数据渲染;📦 当前模式由 $settings['queue_mode'] ?? 'sync' 映射为中文(同步直写 / Cron 定时触发 / CLI 常驻消费)

3.4 手动触发按钮(用户征询项,我的建议:增加)

需求问"是否也可以增加手动点击"。建议增加,理由:

  • cron/cli 模式下管理员改完配置后希望立即验证,不必等 cron 或手动 ssh 起 worker;
  • 复用 worker 同构 handler,实现成本低(约 20 行)。

实现:queueSettings() 的 flush action 调用 flushQueueNow()——对 3 队列各 QueueConsumer::drain(0) 一次(含文件锁防并发,逻辑与 cron_trigger.php 一致):

private function flushQueueNow(): int
{
    $lock = fopen(\app\SplitDB\ShardRouter::dataPath() . '/lock/manual_flush.lock', 'c');
    if (!$lock || !flock($lock, LOCK_EX | LOCK_NB)) return 0;
    $handler = function (string $type, $data, int $taskId): void {
        $payload = is_array($data) ? $data : [];
        if ($type === 'rebuild_search' && !empty($payload['topic_id'])) {
            \app\Helpers\Search::indexThread((int)$payload['topic_id']);
        } elseif ($type === 'stats') {
            \app\Helpers\Settings::runtimeBuild();
        }
    };
    $total = 0;
    for ($i = 0; $i < Queue::QUEUE_COUNT; $i++) {
        $total += (new QueueConsumer(Queue::getQueueDb($i), $handler, 300, 3))->drain(0);
    }
    flock($lock, LOCK_UN); @fclose($lock);
    \app\Helpers\AuditLog::log('admin_action', 'queue', 0, "手动处理队列任务 {$total} 个");
    return $total;
}

3.5 导航与清理(T4)

  • _sidebar.php 搜索设置(L14)后新增:

```html

<a href="/admin/settings/queue" class="sub-link <?php echo ($this->getData('__nav_active') ?? '') === 'settings_queue' ? 'active' : ''; ?>"><?php echo $this->icon('sync', 14); ?> 任务调度</a>

```

(图标:sync/refresh(🔄)或 clock(⏳),均已在 icon 映射内)

  • settings_basic.php:删除「队列任务调度」区块(含 $qmodes 定义与下拉框),恢复为纯基本信息页
  • SettingsController::basic():$keys 移除 'queue_mode'(避免 basic 页覆盖独立页配置)

3.6 交付与回滚点

  • 配置存储不变:settings.queue_mode(值 sync/cron/cli),无迁移需求(老库 get 兜底)
  • 若用户不想要独立模块,回滚 = 还原 4 个文件(index.php 路由、SettingsController、两个视图)

四、交付清单

文件操作
index.php✏️ 改(+2 行路由)
app/Controllers/Admin/SettingsController.php✏️ 改(+queueSettings / queueStatsAggregate / flushQueueNow;basic 去 queue_mode)
app/Views/admin/queue_settings.php🆕 新建(独立页)
app/Views/admin/_sidebar.php✏️ 改(+菜单项)
app/Views/admin/settings_basic.php✏️ 改(删队列调度区块)
update/ 全量同步 + CHANGELOG.md 追加📦 交付

五、验收流程(用户侧)

  1. 后台侧边栏「站点设置」组:搜索设置下方出现「任务调度」菜单项(🔄 图标);
  2. 点击进入 /admin/settings/queue:标题区文案、三模式卡片、队列面板齐全;
  3. 切换「Cron 定时触发」→ 弹防呆确认 → 保存后提示框显示 crontab 命令;队列面板显示当前模式;
  4. 发帖(cron 模式)→ 队列面板「待处理任务 +1」→ 点「立即处理」→ 任务清空、搜索可见;
  5. 「基本信息」页不再含队列调度区块。

六、备注

  • cron_trigger.php(P8 产物)保留不动:虚拟主机无 crontab 权限时仍可作 web 触发备选(本页 Cron 指引按需求显示 crontab 命令,以 cli/worker.php --once 为主,另在提示框附注 cron_trigger.php 备选一行)。
  • 全部改动文件 UTF-8 without BOM + LF,php -l 校验;自测脚本用后即删。
轻量级、高性能、零 MySQL 依赖的PHP社区系统。
| 瀏覽 4 次 | 回覆 0 次

全部回覆 (0)

暫無回覆

請 登入