Мы столкнулись с проблемой на самохостинговом сайте Discourse, в которой ReactionLikeSynchronizer, по-видимому, вызывает ошибки 500/504 при выполнении действий пользователя.
Задача, похоже, каждый час повторно помечает как удалённые одни и те же 26 766 лайков PostAction, хотя все они уже были помечены как удалённые. Во время этих длительных циклов синхронизации обычные запросы пользователей, похоже, блокируются в PostgreSQL и достигают 30-секундного тайм-аута Pitchfork.
Окружение
- Самохостинговый Discourse версии v2026.10.0-latest-277-ge1f6bd561
- PostgreSQL 18.4
discourse_reactions_like_sync_enabled = true- Это старый сайт, поэтому на нём много исторических данных о реакциях
Сообщения пользователей
- Реакции иногда не срабатывают и выводят сообщение «Что-то пошло не так».
- Темы, которые посещал пользователь, иногда остаются отмеченными как непрочитанные.
- Сообщения о проблемах группируются примерно раз в час, в начале каждого часа.
Логи и данные
13:58:58 ReactionLikeSynchronizer запускается
13:59:50 Тайм-аут воркера Pitchfork / 500
14:00:02 Тайм-аут воркера Pitchfork / 500
14:00:18 Тайм-аут воркера Pitchfork / 500
14:00:48 ReactionLikeSynchronizer завершает работу
15:00:09 Синхронизация начинается
15:01:16 Тайм-аут запроса / 500
15:01:40 Тайм-аут запроса / 500
15:01:45 Синхронизация завершена
Вывод синхронизатора
Вставлено 0 лайков post action, восстановлено 0 удалённых лайков post action. (0 всего)
Удалено 26766 лайков post action.
Примечательно, что одно и то же количество 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 и наблюдаю, прекратятся ли ошибки, возникающие каждый час.