进阶 docs.flarum.org 2026-10-15 14:50:53 · 19 阅读
第30章 Flarum 2.x 队列配置与扩展指南
版本:2.x Queue 队列
如果你刚开始搭建,可能用不到队列。但一旦社区达到一定规模,队列就必不可少了。
为什么要关心这个问题?
没有配置队列的 Flarum 站点,会在处理用户请求的过程中执行各种各样的任务,邮件通知就是最典型的例子。Flarum Subscriptions、Friends of Flarum Follow Tags 和 IanM Follow Users 等扩展都会在新动态产生时触发邮件通知。可想而知,一个只有十来个用户的社区不会因此有什么问题;但一旦用户数达到几千,这些通知就会耗费大量时间,直接影响用户在社区里的互动体验。
要化解这个日益沉重的负担,你可以运行一个队列。队列在你的服务器上运行,不与用户及其请求直接交互,但用户请求可以把任务派发给队列。
默认情况下,Flarum 使用 sync 驱动,即在用户请求过程中同步、立即执行任务——虽然方便,但意味着用户必须等每个任务完成才能收到响应。
如何配置队列?
从 Flarum 2.x 开始,database 队列驱动已内置到 Flarum 核心中,无需额外安装扩展。启用方法是在 config.php 中把队列驱动设置为 database:
'queue' => [
'driver' => 'database',
],
数据库队列复用调度器来处理任务,因此你必须将调度器配置为每分钟运行一次,否则无法工作。请参阅调度器指南获取设置说明。 超越数据库驱动 如果需要比数据库驱动能支撑的更高吞吐量,有两个基于 Flarum 队列构建的扩展: * FoF Redis 将队列(以及可选的缓存、会话和配置)迁移到 Redis 兼容服务器(如 Redis 或 Valkey)。任务由标准的 `php flarum queue:work` worker 处理,但针对 Redis 而非数据库——速度更快,且减轻数据库负载。失败的任务也保留在 Redis 中。 * FoF Horizon 基于 FoF Redis 构建(因此必须安装它),并在其上叠加 Laravel Horizon:用受监管、自动平衡的 worker 进程取代单一的 `queue:work`,并提供完整的实时仪表盘,展示吞吐量、等待时间、任务历史及每个队列的指标。它还丰富了管理后台的队列小部件,显示 worker 和状态信息。当你需要在大规模部署中针对不同队列调整 worker 池并详细监控队列健康状况时,请选择 Horizon。 两者均与下文所述的监控、失败任务、暂停及命名队列功能集成。 监控队列 只要启用了真正的队列驱动(除 sync 外的任何驱动),管理后台仪表盘都会显示一个队列小部件,提供一目了然的概览: * Pending(待处理) — 等待处理的任务(包括计划稍后执行的任务)。 * Reserved(已保留) — worker 已拾取并正在当前运行的任务。 * Failed(失败) — 重试次数耗尽的任务。存在失败任务时,此板块会变为按钮,点击可打开失败任务视图。 sync 驱动不显示该小部件,因为它是内联执行任务,没有队列可供监控。 基于队列的扩展可以丰富此小部件。例如,FoF Horizon 在同一卡片上添加 worker 进程、吞吐量和状态板块,并提供链接跳转至其完整仪表盘。 失败任务 抛出异常的任务会被重试,直到达到配置的最大尝试次数;耗尽后,它会被记录为失败而非丢失。失败任务既可以从管理后台仪表盘检查和管理,也可以通过命令行操作。 通过仪表盘小部件中的“Failed”板块,你可以: * 查看每个任务的异常详情; * 重试单个任务(将其推回原队列); * 删除单个任务; * 一次性重试所有失败任务。 命令行也支持相同功能: ```php php flarum queue:failed # 列出失败任务 ```
php flarum queue:retry {id} # 重试某个失败任务(或 `all`)
php flarum queue:forget {id} # 删除某个失败任务
php flarum queue:flush # 删除所有失败任务
失败任务的存储位置取决于驱动类型:内置的 database 驱动将其保存在 queue_failed_jobs 表中,而其他驱动则存储在各自的后端中(例如 FoF Redis 驱动将其保存在 Redis 里)。 暂停队列 你可以在不停止 worker 的情况下暂时停止某个队列处理任务,这在维护、部署或某个扩展行为异常时非常有用。处于暂停状态的任务会保留在队列中,当你恢复队列时,它们会继续处理。 通过管理面板 当论坛使用的驱动不是 sync 时,管理面板的“高级”页面会提供一个队列暂停控件。切换该开关即可暂停(或恢复)论坛的任务处理。 通过命令行 # 暂停默认队列
php flarum queue:pause
# 暂停特定队列(可加连接前缀)
php flarum queue:pause emails
php flarum queue:pause redis:emails
# 暂停该连接下的所有队列
php flarum queue:pause --all
# 恢复所有已暂停的队列(裸命令)
php flarum queue:resume
# 恢复特定队列
php flarum queue:resume emails
# 恢复该连接下的所有队列
php flarum queue:resume --all
不带队列名称的 queue:resume 命令(裸命令)会恢复当前所有已暂停的队列,包括针对整个连接的暂停。若只想恢复某一个队列,请指定其名称。 infoWorker 在启动时加载的代码逻辑用于判断队列是否处于暂停状态。如果在现有安装中启用此功能,请运行一次 php flarum queue:restart,让正在运行的 worker 获取该变更。 无论操作是来自管理面板还是命令行,只要启用了 Audit 扩展,暂停和恢复操作都会记录在审计日志中(标记为 queue.paused / queue.resumed,并包含受影响的连接和队列)。 命名队列 任务并非一律平等——时效性强的通知不应排在缓慢的大批量导出任务之后。Flarum(及其队列驱动)支持多个命名队列,以便你对工作进行隔离和优先级排序。 在 extend.php 中通过 Queue 扩展器将任务类路由到指定命名队列: use Flarum\Extend;
return [
(new Extend\Queue())
->route(\Your\Extension\Jobs\SendExportJob::class, 'exports'),
];
该任务类的每个实例都会被分发到 exports 队列,而分发代码无需任何改动。你可以按需路由任意多个任务类。 路由基类或抽象类会覆盖其所有子类,因此一组相关任务可以通过路由它们共同的父类发送到同一个队列: (new Extend\Queue())
->route(\Your\Extension\Jobs\AbstractExportJob::class, 'exports'),
如果一个任务通过类继承匹配到多条路由,最具体的路由优先生效——任务自身类上的路由会覆盖父类上的路由。分发任务时显式指定的队列则始终优先于任何路由。 之后按优先级顺序运行 worker 处理你关心的队列——每个队列会先被完全清空,再处理下一个: php flarum queue:work --queue=notifications,default,exports
管理工具——仪表盘小部件和按队列暂停功能——会读取一个已知队列名称的注册表(flarum.queue.queues,默认为 ['default'])。将任务路由到自定义命名队列的扩展会把它们追加到该注册表中,从而被工具覆盖。如何声明额外的队列,请参阅相应扩展的文档(如 FoF Redis / FoF Horizon)。
'driver' => 'database',
],
数据库队列复用调度器来处理任务,因此你必须将调度器配置为每分钟运行一次,否则无法工作。请参阅调度器指南获取设置说明。 超越数据库驱动 如果需要比数据库驱动能支撑的更高吞吐量,有两个基于 Flarum 队列构建的扩展: * FoF Redis 将队列(以及可选的缓存、会话和配置)迁移到 Redis 兼容服务器(如 Redis 或 Valkey)。任务由标准的 `php flarum queue:work` worker 处理,但针对 Redis 而非数据库——速度更快,且减轻数据库负载。失败的任务也保留在 Redis 中。 * FoF Horizon 基于 FoF Redis 构建(因此必须安装它),并在其上叠加 Laravel Horizon:用受监管、自动平衡的 worker 进程取代单一的 `queue:work`,并提供完整的实时仪表盘,展示吞吐量、等待时间、任务历史及每个队列的指标。它还丰富了管理后台的队列小部件,显示 worker 和状态信息。当你需要在大规模部署中针对不同队列调整 worker 池并详细监控队列健康状况时,请选择 Horizon。 两者均与下文所述的监控、失败任务、暂停及命名队列功能集成。 监控队列 只要启用了真正的队列驱动(除 sync 外的任何驱动),管理后台仪表盘都会显示一个队列小部件,提供一目了然的概览: * Pending(待处理) — 等待处理的任务(包括计划稍后执行的任务)。 * Reserved(已保留) — worker 已拾取并正在当前运行的任务。 * Failed(失败) — 重试次数耗尽的任务。存在失败任务时,此板块会变为按钮,点击可打开失败任务视图。 sync 驱动不显示该小部件,因为它是内联执行任务,没有队列可供监控。 基于队列的扩展可以丰富此小部件。例如,FoF Horizon 在同一卡片上添加 worker 进程、吞吐量和状态板块,并提供链接跳转至其完整仪表盘。 失败任务 抛出异常的任务会被重试,直到达到配置的最大尝试次数;耗尽后,它会被记录为失败而非丢失。失败任务既可以从管理后台仪表盘检查和管理,也可以通过命令行操作。 通过仪表盘小部件中的“Failed”板块,你可以: * 查看每个任务的异常详情; * 重试单个任务(将其推回原队列); * 删除单个任务; * 一次性重试所有失败任务。 命令行也支持相同功能: ```php php flarum queue:failed # 列出失败任务 ```
php flarum queue:retry {id} # 重试某个失败任务(或 `all`)
php flarum queue:forget {id} # 删除某个失败任务
php flarum queue:flush # 删除所有失败任务
失败任务的存储位置取决于驱动类型:内置的 database 驱动将其保存在 queue_failed_jobs 表中,而其他驱动则存储在各自的后端中(例如 FoF Redis 驱动将其保存在 Redis 里)。 暂停队列 你可以在不停止 worker 的情况下暂时停止某个队列处理任务,这在维护、部署或某个扩展行为异常时非常有用。处于暂停状态的任务会保留在队列中,当你恢复队列时,它们会继续处理。 通过管理面板 当论坛使用的驱动不是 sync 时,管理面板的“高级”页面会提供一个队列暂停控件。切换该开关即可暂停(或恢复)论坛的任务处理。 通过命令行 # 暂停默认队列
php flarum queue:pause
# 暂停特定队列(可加连接前缀)
php flarum queue:pause emails
php flarum queue:pause redis:emails
# 暂停该连接下的所有队列
php flarum queue:pause --all
# 恢复所有已暂停的队列(裸命令)
php flarum queue:resume
# 恢复特定队列
php flarum queue:resume emails
# 恢复该连接下的所有队列
php flarum queue:resume --all
不带队列名称的 queue:resume 命令(裸命令)会恢复当前所有已暂停的队列,包括针对整个连接的暂停。若只想恢复某一个队列,请指定其名称。 infoWorker 在启动时加载的代码逻辑用于判断队列是否处于暂停状态。如果在现有安装中启用此功能,请运行一次 php flarum queue:restart,让正在运行的 worker 获取该变更。 无论操作是来自管理面板还是命令行,只要启用了 Audit 扩展,暂停和恢复操作都会记录在审计日志中(标记为 queue.paused / queue.resumed,并包含受影响的连接和队列)。 命名队列 任务并非一律平等——时效性强的通知不应排在缓慢的大批量导出任务之后。Flarum(及其队列驱动)支持多个命名队列,以便你对工作进行隔离和优先级排序。 在 extend.php 中通过 Queue 扩展器将任务类路由到指定命名队列: use Flarum\Extend;
return [
(new Extend\Queue())
->route(\Your\Extension\Jobs\SendExportJob::class, 'exports'),
];
该任务类的每个实例都会被分发到 exports 队列,而分发代码无需任何改动。你可以按需路由任意多个任务类。 路由基类或抽象类会覆盖其所有子类,因此一组相关任务可以通过路由它们共同的父类发送到同一个队列: (new Extend\Queue())
->route(\Your\Extension\Jobs\AbstractExportJob::class, 'exports'),
如果一个任务通过类继承匹配到多条路由,最具体的路由优先生效——任务自身类上的路由会覆盖父类上的路由。分发任务时显式指定的队列则始终优先于任何路由。 之后按优先级顺序运行 worker 处理你关心的队列——每个队列会先被完全清空,再处理下一个: php flarum queue:work --queue=notifications,default,exports
管理工具——仪表盘小部件和按队列暂停功能——会读取一个已知队列名称的注册表(flarum.queue.queues,默认为 ['default'])。将任务路由到自定义命名队列的扩展会把它们追加到该注册表中,从而被工具覆盖。如何声明额外的队列,请参阅相应扩展的文档(如 FoF Redis / FoF Horizon)。