ReactionLikeSynchronizer rielabora ogni ora i like di PostAction già cestinati

Abbiamo riscontrato un problema su un sito Discourse self-hosted in cui ReactionLikeSynchronizer sembra causare errori 500/504 per le azioni degli utenti.

Il job sembra ripetere ogni ora l’operazione di spostamento nel cestino delle stesse 26.766 reazioni PostAction, anche se tutte sono già state marcate come eliminate. Durante queste esecuzioni di sincronizzazione più lunghe, le richieste normali degli utenti sembrano bloccarsi in PostgreSQL e raggiungere il timeout di 30 secondi di Pitchfork.

Ambiente

  • Discourse self-hosted versione v2026.10.0-latest-277-ge1f6bd561
  • PostgreSQL 18.4
  • discourse_reactions_like_sync_enabled = true
  • Si tratta di un sito più datato, quindi è presente una grande quantità di dati storici sulle reazioni

Segnalazioni degli utenti

  • A volte le reazioni falliscono e producono il messaggio “Qualcosa è andato storto”.
  • A volte i topic visitati da un utente rimangono marcati come non letti
  • Le segnalazioni si concentrano circa una volta all’ora, all’inizio dell’ora.

Log e dati

13:58:58 Avvio di ReactionLikeSynchronizer
13:59:50 Timeout worker Pitchfork / 500
14:00:02 Timeout worker Pitchfork / 500
14:00:18 Timeout worker Pitchfork / 500
14:00:48 ReactionLikeSynchronizer completato

15:00:09 Avvio sincronizzazione
15:01:16 Timeout richiesta / 500
15:01:40 Timeout richiesta / 500
15:01:45 Sincronizzazione completata

Output del sincronizzatore

Inserite 0 reazioni post action, recuperate 0 reazioni post action nel cestino. (0 totale)
Spostate nel cestino 26766 reazioni post action.

In modo notevole, lo stesso conteggio di 26766 appare in ogni esecuzione verificata.

Contenuto del database

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

Note

Per quanto vale, sembra che ReactionLikeSynchronizer#trash_excluded_post_actions corrisponda a reazioni che sono state escluse anche se sono già state eliminate. La query è la seguente:

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

In modo notevole, questa non esclude le azioni eliminate tramite qualcosa come AND post_actions.deleted_at IS NULL.

Questo sembra comportare che lo stesso insieme di righe venga rielaborato ogni ora. Posso aggiungere uno stack trace, se necessario.

Come soluzione temporanea, ho disabilitato discourse_reactions_like_sync_enabled e sto monitorando se gli errori smettono di verificarsi ogni ora.

Modificato per correggere i refusi e la query nella sezione “Note”.