应对10分钟延迟

我计划在一个沿海地区天气预报网站上使用 wp-discourse 插件,该网站通常每天有 10-20k 页面浏览量,但在恶劣天气事件期间,有时会达到每天 150-200 万页面浏览量,约有 500-700k 访客。该网站及其托管策略已经过多次恶劣天气事件的考验,并且在压力下运行良好,这主要归功于精心设计和 Cloudflare 的大力帮助。

网站用户习惯了通过原生 WordPress 评论提供的低摩擦评论体验,因此需要一些调整(例如让他们习惯点击“继续讨论于…”链接),用户界面团队已准备好应对。

但是,他们无法容忍评论发布后到显示在每日 WordPress 帖子页面上之间长达 10 分钟的可变延迟。他们希望新评论(达到配置的限制)在发布后立即显示在主页上,类似于原生 WP 评论发布后立即显示的方式。

在尝试了内置选项以使帖子立即显示而没有 nginx 的 fastcgi 缓存、WordPress 或浏览器缓存干扰新评论在刷新后出现后,我添加了以下两个 mu-插件来缓解此问题,并使新发布的评论在刷新后立即显示在 WordPress 端:

wp-discourse-transient-killer.php
wp-discourse-cache-header-fix.php

这解决了我的问题:新发布的评论到 WordPress 创建的 Discourse 线程现在在刷新后立即显示在 WordPress 帖子下方。

但我在这里的能力已经接近极限了——我这样做会破坏/搞砸/削弱什么?

我不太关心通过评论端点被访问每日天气预报页面(带有嵌入式 Discourse 评论)的访问者不断访问而增加网络主机的额外负载——这是一个可以通过花钱解决的问题。我的主要要求是避免 20,000 多名用户给我发邮件,询问为什么他们发布的评论没有立即显示在主页上。

这是正确的方法吗?我这样做明智吗?它会带来我没有预料到的额外安全或性能问题吗?基本上,我这样做是不是在搞砸事情?

谢谢 :slight_smile:

Hmm,我不明白为什么这会起作用,因为

而你的插件

add_action( 'wpdc_after_webhook_post_update', function( $topic_ids ) {
    foreach ( (array)$topic_ids as $topic_id ) {
        delete_transient( 'wpdc_comment_html_' . $topic_id );
    }
}, 11 );

你不是在混淆传递给操作的(Wordpress)$post_id 和用作瞬态键的(Discourse)topic_id 吗?

我期望你的插件看起来像这样

add_action( 'wpdc_after_webhook_post_update', function( $post_ids) {
    foreach ( (array)$post_ids as $post_id ) {
        $topic_id = get_post_meta( $post_id, 'discourse_topic_id', true );
        delete_transient( 'wpdc_comment_html_' . $topic_id );
    }
}, 11 );

另一方面,你说这能起作用?:thinking:

@Lee_Ars,你能先确认一下你设置了评论 webhook 吗?

它的工作方式如下:

  1. Discourse 中出现新帖子。
  2. 将 webhook 有效负载发送到 Wordpress。
  3. WP discourse 更新帖子的评论数,并设置一个自定义帖子字段 wpdc_sync_post_comments
  4. 如果设置了 wpdc_sync_post_comments,Discourse 评论将在 Wordpress 帖子加载时同步,无论同步周期如何(即 10 分钟延迟)。

在深入研究缓存之前,我想先确保这一点已到位。如果已到位,也许还可以打开“详细的 Webhook 日志”并验证你在 Discourse 中发布新帖子时是否收到 webhook 请求。

1 个赞

嗨 Angus!是的,已确认,“同步评论数据” webhook 选项在 WP 端已启用,并且我在 Discourse 端创建了 webhook,ping 成功。WP 插件的日志显示在正确的时间戳下有 comment.INFO: sync_comments.success 消息:

[2025-07-07 14:16:38] connection.INFO: check_connection_status.successful_connection
[2025-07-07 14:16:38] connection.INFO: check_connection_status.valid_scopes
[2025-07-07 20:11:31] comment.INFO: sync_comments.success {"post_id":786}
[2025-07-07 20:25:03] comment.INFO: sync_comments.success {"post_id":786}
[2025-07-07 20:32:14] comment.INFO: sync_comments.success {"post_id":786}
[2025-07-07 20:44:15] comment.INFO: sync_comments.success {"post_id":786}
[2025-07-07 21:00:39] comment.INFO: sync_comments.success {"post_id":786}
[2025-07-07 21:01:42] comment.INFO: sync_comments.success {"post_id":786}
[2025-07-07 21:15:40] comment.INFO: sync_comments.success {"post_id":786}

只是,即使有这些成功消息,现有访问者(至少是我,在 Mac 上的 Firefox/Safari/Chrome、Win10 PC 上的 Firefox/Chrome/Edge 以及 iOS 上的 Safari 上进行了多次测试)仍然收到一个缓存的 /wp-json/wp-discourse/v1/discourse-comments 端点,其 cache-control 标头设置为非零值。如果我在 Chrome 中执行 ctrl-shift-f5(或在其他浏览器中执行等效操作)来强制刷新时绕过本地缓存,一切都会正常工作,并且会显示新的嵌入式帖子。

在安装了 mu-plugins 后,该端点显示 cache-control 设置为 no-store no-cache 等,并且原始问题行为不会出现——只需访问 WP 帖子或使用常规刷新按钮刷新它,就会显示新的嵌入式评论。

我启用了详细的 webhook 日志记录并发布了一个测试帖子,当我创建新帖子时,一切看起来都正常:

webhook_topic.INFO: update_topic_content.update_post_metadata_success {"post_ids":"786"}

一切 似乎 都正常工作,但我仍然不太明白原始问题行为为何会出现,或者它是否源于我这边被忽略的某个问题。(很有可能!)

哎呀,抱歉,我确定你说得对,我搞砸了——昨天是很漫长的一天,而且正如我所说,我在这里的能力已经接近极限了。它确实 起作用了,但现在我担心我看到的“修复”行为只是它以一种新的方式损坏了。(谢谢你!我已经更新了“瞬态杀手”插件以使用正确的参数了!)

谢谢,还有最后一件事需要澄清。这个 WP Discourse 设置(在“评论”中)是开启的吗?

我已尝试启用或禁用 Cache Comment HTML 设置,并且这似乎对问题行为没有影响。我目前将其禁用,但可以将其设置为对故障排除有帮助的任何设置。

如果禁用了该设置,您将不会注意到 topic_id / post_id 混淆,因为在这种情况下该插件不起任何作用。无缓存 → 删除错误的缓存无关紧要。

如果启用了该设置,那么您应该会注意到该插件无法正常工作。

也就是说,如果您想进行故障排除,则应启用该设置。

1 个赞

好的,作为您案件的第一项措施,我建议:

  1. 禁用“缓存评论 HTML”;以及
  2. 移除 https://www.bigdinosaur.org/r/wp-discourse-transient-killer.txt 插件,因为正如 Richard 所观察到的,它目前没有任何作用。

如果这不能解决问题,那么问题就出在其他形式的缓存上。接下来需要回答的问题是:

  1. 您(和/或您的托管提供商)为 WordPress 使用了哪些缓存解决方案?
  2. 如果 https://www.bigdinosaur.org/r/wp-discourse-cache-header-fix.txt 解决了问题,它的具体行为是如何使 1 中应用的任何缓存失效的?

查看 wp-discourse-cache-header-fix,我看到其中一个修复是针对 load-comments.js 的。您是否启用了此设置?

这是自托管的 WP,运行在 nginx+php-fpm 8.3 上,使用 nginx fast-cgi 缓存动态内容,并使用 Redis 对象缓存(启用了 object cache drop-in)。没有其他层(没有 CDN、没有 CF、没有本地的 Varnish 或除 nginx fast-cgi 缓存之外的其他本地缓存)。清除 nginx fast cgi 缓存(激进地执行 rm -rf /etc/nginx/cache/*)对问题行为没有影响——即使在清除缓存目录并重启 nginx 和 php-fpm 后,仍然会提供过时的结果。

我确实启用了 Ajax 评论加载,是的,但同样,将其关闭(并清除 nginx 缓存以及重启 nginx 和 php-fpm 以防万一)对问题行为没有影响。浏览器仍然提供过时的评论。

选项已切换,transient-killer 已删除。问题行为没有改变。

它应用的效果似乎是提供一个没有缓存的 cache-control 标头,而不是一个指定缓存时间的标头。在没有它的情况下,我的浏览器似乎非常倾向于从其磁盘缓存提供 wp-json/wp-discourse/v1/discourse-comments 端点的过时缓存版本;如前所述,我必须按 Shift-Ctrl-F5(或等效操作)才能强制无缓存刷新。

问题行为似乎在浏览器端,而不是在持久的服务器缓存中。我所能访问的每个操作系统上的每个浏览器都在这样做。

好的。为了让我100%清楚。当您有

  • 已验证可用的评论 webhook
  • 评论 HTML 缓存关闭
  • AJAX 加载关闭
  • 无 CDN
  • 无 Cloudfront
  • 无 WordPress 缓存插件
  • PHP 日志中无相关警告或错误

您确定它不起作用吗?

如果使用该设置不起作用,在没有仔细查看的情况下,我有点无能为力,并且会默认使用

  • AJAX 加载开启
  • 您的 wp-discourse-cache-header-fix.php 修复

这正是我怀疑对您有效的原因。如果该方法有效,那么您应该选择它。

这里有一个快速的 imgur 图库 包含了我当前插件设置的截图,供您参考。

确认没有 CDN,没有 Cloudfront 或 Cloudflare 中的任何一个,除了 Nginx helper(用于帮助 WP 按需使 nginx fast-cgi 缓存失效)之外没有其他缓存插件。

同时确认 php-fpm 或 nginx 错误日志中没有相关内容。

天啊,老兄,我希望它能起作用。我为此已经花了大约 30 个小时,中间休息了些时间睡觉。我可能有点眼花了,呵呵。

嗯,我懂你。休息一天吧。我明天会试着照着你的配置来重现这个问题。

2 个赞

如果我不能摸索出一个解决方案,并且如果您愿意,我很乐意提供一些临时的本地访问权限(包括WordPress博客、Discourse论坛和/或底层主机)以进行故障排除。我绝对不是想白嫖劳力。不过,如果确实需要花费时间,我很乐意为您的服务付费。

好的,这是我尝试(但失败了)重现您问题的视频:

接下来,我想让您尝试 此过滤器

感谢 @angus - 无法重现反而让我感觉好多了,因为这意味着是我做错了而不是真的有什么问题 :smiley:

我今天有时间排查问题时会加上那个过滤器,然后回报 :+1:

1 个赞

一个月多一点后回复,以完成此事的跟进——我在部署到完全生产时仍然遇到一些奇怪的问题(prod 网站带有 discourse 嵌入的示例 prod 网站帖子实际的 discourse 论坛),但一切都在可控之中。我将把任何剩余的延迟/延误问题归因于 Wordpress + Discourse + Cloudflare 这种复杂的层叠组合,以及我在实际风暴导致流量高峰期间保持所有这些东西运行的激进缓存策略。

感谢您花时间回复,@angus <3

1 个赞

抱歉又一次“顶”了这个问题,但我想跟进并报告我找到了问题的根源!一如既往,这都是我自己的错。

简而言之,我将常见的 PHP 位置块(location block)详细信息保存在 /etc/nginx/snippets/ 下的一个代码片段(snippet)中,这样我就可以在多个 vhost 文件中包含它们,而无需每次都重复复制代码。我检查那个代码片段已经很久了(可能好几年了),果然,里面有一个多余的 add_header Cache-Control "public, max-age=7200";,它被应用到了那个位置块(location block)输出的所有内容上。

所以我把它删掉了,清空了所有缓存层,结果,问题行为消失了。

再次感谢你花时间与我一起解决问题,@angus,尽管这最终又一次是我自己造成的 Discourse 问题 :people_hugging:

3 个赞

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.