我们在一个自托管的 Discourse 站点上遇到了一个问题:ReactionLikeSynchronizer 似乎在处理用户操作时触发了 500/504 错误。
该任务似乎每小时都在重复将同一批 26,766 个 PostAction 点赞标记为已删除(trashed),尽管它们此前已经被标记为删除。在这些较长的同步运行期间,正常的用户请求似乎在 PostgreSQL 中被阻塞,并触发了 Pitchfork 的 30 秒超时。
环境
- 自托管 Discourse,版本为 v2026.10.0-latest-277-ge1f6bd561
- PostgreSQL 18.4
discourse_reactions_like_sync_enabled = true- 这是一个较旧的站点,因此存在大量历史表情数据
用户反馈
- 表情反应有时失败,并显示“出错了”(Something went wrong)的消息。
- 用户访问过的主题有时仍被标记为未读
- 报告集中在每小时整点附近
日志和数据
13:58:58 ReactionLikeSynchronizer 启动
13:59:50 Pitchfork worker 超时 / 500
14:00:02 Pitchfork worker 超时 / 500
14:00:18 Pitchfork worker 超时 / 500
14:00:48 ReactionLikeSynchronizer 完成
15:00:09 同步启动
15:01:16 请求超时 / 500
15:01:40 请求超时 / 500
15:01:45 同步完成
同步器输出
插入了 0 个帖子操作点赞,恢复了 0 个已删除的帖子操作点赞。(总计 0)
将 26766 个帖子操作点赞标记为已删除。
值得注意的是,在我检查的每次运行中,26766 这个数字都保持不变。
数据库内容
SELECT
COUNT(*) AS total,
COUNT(*) FILTER (WHERE pa.deleted_at IS NULL) AS currently_active,
COUNT(*) FILTER (WHERE pa.deleted_at IS NOT NULL) AS already_trashed
FROM post_actions pa
JOIN discourse_reactions_reaction_users ru
ON ru.user_id = pa.user_id
AND ru.post_id = pa.post_id
JOIN discourse_reactions_reactions r
ON r.id = ru.reaction_id
WHERE pa.post_action_type_id = 2
AND r.reaction_value IN (
'-1','poop','face_with_symbols_on_mouth','enraged_face',
'face_vomiting','nauseated_face','angry','kitchen_knife',
'water_pistol','bomb','clown_face','unamused_face','roll_eyes',
'confused','smirking_face','disappointed_face','pensive_face',
'lying_face','weary_face','tired_face','confounded_face',
'persevering_face','smiling_face_with_horns','angry_face_with_horns',
'cigarette','person_gesturing_no','prohibited','no_entry',
'dagger','cross_mark'
);
total | currently_active | already_trashed
-------+------------------+-----------------
26766 | 0 | 26766
备注
仅供参考,看起来 ReactionLikeSynchronizer#trash_excluded_post_actions 会匹配那些已被排除的点赞,即使它们已经被删除。查询如下:
UPDATE post_actions
SET deleted_at = NOW()
FROM discourse_reactions_reaction_users ru
INNER JOIN discourse_reactions_reactions
ON discourse_reactions_reactions.id = ru.reaction_id
WHERE post_actions.user_id = ru.user_id
AND post_actions.post_id = ru.post_id
AND post_actions.post_action_type_id = :like
AND discourse_reactions_reactions.reaction_value IN (:excluded_from_like)
RETURNING post_actions.id
值得注意的是,这并没有通过类似 AND post_actions.deleted_at IS NULL 的条件来排除已删除的操作。
这似乎导致同一组行每小时都被重新处理。如有必要,我可以提供堆栈跟踪。
作为临时解决方案,我禁用了 discourse_reactions_like_sync_enabled,并正在监控错误是否不再每小时发生。