
守护进程:温暖的工作者,无启动成本
27 Mar 2026
每个 PHP 请求在进行任何实际工作之前,传统上都需要支付一个小的税费:引导框架,连接应用程序,然后处理请求。FrankenPHP 的 worker 模式已经通过在请求之间保持应用程序驻留在内存中,去除了大部分开销。Phlo Daemon 采用了相同的理念,并将其扩展到所有非正常的 HTTP 请求。
实际上需要守护进程的内容
有三件事情可以从一个已经温暖且正在运行的进程中受益:Phlo Realtime(在之前的帖子中介绍过)、当一个请求扩展为多个调用时的运行时助手(phlo_sync、phlo_async、await、phlo_stream)以及计划任务。守护进程是一个工作池,可以运行任何 Phlo 目标、路由、方法或任务,而无需为每次调用支付新的启动成本。
prop tasks => arr(
cleanup: arr(do: 'session::prune', every: '15 minutes'),
report: arr(do: 'reports::sendWeekly', weekly: 'monday 08:00'),
)
在应用程序本身没有 cron 语法,只有 every:、daily: 或 weekly: 针对一个普通的调度读取器。无论是否有守护进程,该调度都存在于 %app->tasks 中;改变的是触发器。没有守护进程时,一行通用的 cron 语句每分钟调用一次 tasks::run,资源本身决定实际到期的任务。有了守护进程,主机映射中的每个应用程序都内置了同样的每分钟滴答,因此那一行 cron 语句也就不再需要。
运行时助手的工作方式相同:如果没有设置 daemon 常量,phlo_async/await 仍然作为一次性后台进程运行,每个进程都需要重新启动。在 phlo_app(...) 中设置 daemon: 3001,同样的调用将路由到常驻工作池,而不是每次调用都需要启动。最大的优势恰恰在于一个请求分散成多个调用时,await() 超过一百个缺失的翻译在一次性路径上是一百次启动,而在有守护进程的温暖池中则是一次性调度一百次。
结构上的可选性
核心 Phlo 不需要守护进程,它添加的两个功能在没有守护进程的情况下表现不同。Realtime 确实没有后备方案:没有守护进程意味着没有 WebSocket 服务器,完全停止。任务确实有一个:没有守护进程时,每分钟调用一次 tasks::run 的单行 cron 语句正好完成守护进程内置滴答的功能,只是需要管理一个 crontab 条目而不是零个。这在操作上很重要:您可以完全不使用守护进程来开发和部署 Phlo 应用,依靠 cron 进行调度,并在 Realtime 或重请求实际需要时随时添加守护进程,而无需重构已经存在的内容。
生产中的形态
在生产布局中,守护进程是与 FrankenPHP 并排的侧车,二者由同一服务器平台连接:/server-setup 构建器为 FrankenPHP 提供一个真实的 systemd 单元,并在 pm2 下运行守护进程,pm2 本身注册到 systemd,以便在启动时恢复。它是箱子上的另一个温暖进程,而不是一个单独的舰队来操作。重要的调优是工作进程数量与可用内存的关系,这与任何常驻进程运行时需要的调优相同,并且它的扩展方式与 Phlo 其余部分相同:水平扩展,负载均衡器后面有相同的节点,每个节点为其自己的应用程序运行自己的守护进程。
关键不是“cron 是坏的。”而是调度工作和实时工作在形态上足够接近,作为一个在没有启动成本的情况下运行您代码的后台进程,它们应该有一个答案,而不是两个无关的答案。