8 月 20 日,WordPress 7.1 版本上线。几小时后,大量使用 WP Rocket 插件的网站出现致命错误,部分站点前端直接挂掉,后台管理界面也陷入瘫痪,用户无法自行修复。
WP Rocket 团队承认这是他们的责任,因为当时未能在第一时间采取有效行动。他们通过这份详细报告梳理了事故全过程,分析了响应迟缓的原因,并说明了防止再次发生的改进措施。
故障根源解析
WP Rocket 内置了一个与 Cloudflare 交互的小型模块,无论网站是不是使用 Cloudflare,该模块始终处于激活状态。在其清理机制中,该模块会调用 PHP 的 substr() 函数来处理 WordPress 在两个特定钩子上生成的回调 ID。在 7.1 版本之前,这个 ID 始终是字符串类型。由于 PHP 8 执行严格类型检查,如果传入非字符串参数,程序不会静默继续,而是直接抛出致命错误。
WordPress 7.1 改变了这些回调 ID 的生成方式。在特定条件下,ID 可能会以整数形式返回,而非字符串。核心维护者 Weston Ruter 在 8 月 21 日确认了这一点,并将其定性为破坏性变更。一位核心贡献者随后提交了工单,提出了修复方案,预计该修复将包含在 WordPress 7.1.1 中。
触发该问题需要同时满足特定条件:即另一个激活的插件以特定方式注册了回调。团队审查了 WordPress.org 上最常用的 200 个插件、用户报告及公开的 GitHub 活动,锁定了具体触发源。以下是已确认会触发问题的插件,需明确的是,这些插件本身并无过错,只是恰好撞上了 WP Rocket 的漏洞:
- Elementor Pro只要用户拥有有效许可证并激活插件,即可能触发。
- Elementor Free若启用了实验性的 e_atomic_elements 设置,则可能触发。
- Redirection for Contact Form 7插件激活后即刻可能触发。
简而言之,问题出现在 WordPress 7.1、PHP 8.x、WP Rocket 和至少一个以特定方式注册回调的其他插件共同存在的组合中。虽然条件看似特定,但在实际环境中特别常见。基于确认的触发插件及用户更新模式,团队估计约 27% 的 WP Rocket 网站处于风险中,其中大约 10% 实际受到了影响。
事故时间线梳理
7 月 6 日。一名 WP Rocket 用户在 GitHub 上针对 WordPress 7.1 alpha 版本提出了问题报告,准确指出了 Bug 并建议了最终采用的修复方案。QA 团队当天介入,运行了针对 WordPress 夜间构建版本的自动化测试,所有测试均通过。他们尝试复现问题但失败,此后该报告再无更新。接下来的几周,少数客户也遇到相同的致命错误并开单,当时均通过回退到稳定的 WordPress 版本解决,未关联到之前的 GitHub 报告。
7 月 15 日。WordPress 7.1 首个 beta 版本发布,其中已包含该 Bug。团队针对该 beta 版本的自动化与手动测试全部通过,所以将 WP Rocket 标记为兼容 7.1 版本。
8 月 19 日 23:39 CEST。WordPress 7.1 候选版本在发布会上推出,当晚开始出现关于致命错误的支持工单。虽然此时不在插件团队的常规工作时间,但另一团队的开发人员注意到升级警告,深入调查并确认了根本原因。
8 月 20 日 00:35 CEST。团队获得了手动修复方案。鉴于尚未通过常规 QA 验证,为避免推广未经验证的临时方案,他们将该修复直接发送给所有已开立支持工单的用户,并告知官方更新正在途中。
8 月 20 日 02:18 CEST。WordPress 7.1 正式发布。所有启用自动更新的站点开始更新,从此时起均可能遭遇该 Bug。
8 月 20 日 04:08 CEST。支持团队发布了涵盖该问题及可用临时方案的文档。
8 月 20 日 07:30 CEST。WP Rocket 插件团队开始工作并接手此事。15 分钟内完成公开沟通:产品内通知、社交媒体动态、状态页更新和对所有相关 GitHub 问题的回复,引导用户查看支持文章并告知修复即将发布。
8 月 20 日 10:11 CEST。WP Rocket 3.23.2.2 版本发布,已通过自动化测试和针对性手动测试验证。团队监控所有渠道确认修复有效,一切正常。
8 月 21 日。团队向所有活跃的 WP Rocket 客户发送邮件,解释事故原因,并建议在升级到 WordPress 7.1 之前先更新 WP Rocket。
测试体系为何失效
鉴于影响范围之广,这是最关键的问题。测试流程原本如下:在拉取请求阶段,每个变更都需经过另一位开发人员的审查,包括手动测试和确认在多个 WordPress 及 PHP 版本上自动化测试通过。这些测试在 GitHub 仓库中公开可见。合并后,QA 工程师针对最新的 WordPress 夜间构建版本验证变更,以在合并前捕获回归。
合并后,开发版本持续运行约 100 个自动化端到端测试,覆盖 NGINX 和 Apache,针对最新的 WordPress 版本(包括 beta 和候选版)。该测试套件也是公开的,它检查与特定第三方组件的兼容性,包括 Query Monitor、Imagify、Cloudflare、WPML、Divi、Avada、Astra、Flatsome、Storefront、Hello Elementor、Neve、Kadence、GeneratePress、Genesis Sample 和 OceanWP。
这份清单并非基于用户最常用的插件制定,而是多年间机会主义增长的结果:每当改进与某插件或主题的兼容性时,就添加自动化测试以防后续回归。这种增长方式虽合理,但留下了真实空白,Elementor Pro 不在该清单上便是其中之一。
在新版本发布前,团队还会在内部发布候选版本供全员做额外探索性测试,并在几天内逐步向客户推出,而非一次性全量发布,以便在问题扩散前捕获并推送热修复。不过,这些问题并未被捕获,因为该故障仅在自动化检查未包含的第三方组件上出现,且近期版本的手动测试计划也未涵盖这些组件。
整改措施与后续计划
明确 GitHub 问题筛选责任人。7 月 6 日的报告虽被审查,但从未分配给责任人,初始检查未能复现后便消失在视野中。现已建立明确的问责机制:所有报告均经过筛选、分类,在相关时升级至产品团队,并随新评论保持更新。
有目的地重构测试基准。当前的兼容性测试套件反映的是多年来的增量添加,而非基于用户实际运行情况的刻意规划。团队正在构建合理的清单,从最常与 WP Rocket 一起使用的顶级插件和主题入手,并基于第三方流行度和兼容性工作持续扩展。WordPress 生态系统过于开放,无法承诺覆盖所有可能配置,但这份清单将基于意图而非历史构建。
立即实施小型修复。Cloudflare 模块此前在每个站点上运行,无论是不是使用 Cloudflare。现已将其置于检查 Cloudflare 插件是不是实际激活的条件之后,确保无需 Cloudflare 的站点完全不运行该特定代码路径。
后续待办事项:在完成上述整改后,团队还将缩短从内部升级到公开沟通的时间,削减本不应加载的未使用代码路径,并缩短已知需热修复时的验证与发布时间。
