Encontramos um problema em um site Discourse auto-hospedado em que o ReactionLikeSynchronizer parece estar disparando erros 500/504 para ações dos usuários.
O job parece estar repetidamente marcando como lixadas as mesmas 26.766 curtidas de PostAction a cada hora, mesmo que todas já tenham sido marcadas como excluídas. Durante essas execuções de sincronização mais longas, as solicitações normais dos usuários parecem ficar bloqueadas no PostgreSQL e atingir o tempo limite de 30 segundos do Pitchfork.
Ambiente
- Discourse auto-hospedado na versão v2026.10.0-latest-277-ge1f6bd561
- PostgreSQL 18.4
discourse_reactions_like_sync_enabled = true- Este é um site antigo, portanto há uma grande quantidade de dados históricos de reações
Relatos dos Usuários
- As reações às vezes falham e produzem a mensagem “Algo deu errado”.
- Tópicos visitados por um usuário às vezes permanecem marcados como não lidos
- Os relatos estão agrupados em torno de uma vez por hora, no início da hora.
Logs e Dados
13:58:58 ReactionLikeSynchronizer inicia
13:59:50 Tempo limite do worker do Pitchfork / 500
14:00:02 Tempo limite do worker do Pitchfork / 500
14:00:18 Tempo limite do worker do Pitchfork / 500
14:00:48 ReactionLikeSynchronizer concluído
15:00:09 sincronização inicia
15:01:16 tempo limite da solicitação / 500
15:01:40 tempo limite da solicitação / 500
15:01:45 sincronização concluída
Saída do Sincronizador
Inseridas 0 curtidas de post action, recuperadas 0 curtidas de post action lixadas. (0 no total)
Lixadas 26766 curtidas de post action.
Notavelmente, a mesma contagem de 26766 aparece em todas as execuções que verifiquei.
Conteúdo do Banco de Dados
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
Observações
Para o que vale, parece que ReactionLikeSynchronizer#trash_excluded_post_actions corresponde a curtidas que foram excluídas, mesmo que já tenham sido removidas. A consulta parece ser esta:
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
Notavelmente, isso não exclui ações já removidas por meio de algo como AND post_actions.deleted_at IS NULL.
Isso parece resultar no mesmo conjunto de linhas sendo reprocessado a cada hora. Posso adicionar um stack trace, se necessário.
Como solução temporária, desativei discourse_reactions_like_sync_enabled e estou monitorando se os erros deixam de ocorrer a cada hora.