Jobs::SyncTopicUserBookmarked en un bucle usando el 100% de CPU

En las últimas ~18h, nuestro servidor está utilizando cerca del 100% de CPU.

Mirando Sidekiq, está ocupado ejecutando los mismos 5 trabajos:

Siempre está en “Justo ahora” y parecen estar siempre volviendo a ejecutar esos mismos 3 IDs de tema.

Intenté reiniciar Discourse, pero la situación continuó.

No estoy seguro si está relacionado, pero esto comenzó ~24h después de que actualizamos de 3.3.3 a 3.3.4. No veo ningún cambio reciente en app/jobs/regular/sync_topic_user_bookmarked.rb y no pude detectar ningún cambio en 3.3.4 que pudiera estar relacionado, pero no conozco la base de código.

¿Alguna idea de lo que podría estar pasando?

Una actualización de esto. Acabamos de notar que los 3 IDs de tema sobre los que las tareas se ejecutan repetidamente son temas a los que activamos la eliminación automática de respuestas ayer, cerca de cuando esto comenzó. Todos son temas muy grandes.

Así que conocemos el desencadenante, pero el SQL que se repite no parece estar haciendo ningún procesamiento por lotes, por lo que no veo por qué se está ejecutando una y otra vez.

¿Está siendo activado por algún otro trabajo que todavía está eliminando el gran número de respuestas y Jobs::SyncTopicUserBookmarked se ejecuta por cada publicación eliminada? ¿O es un error?

Eliminamos la eliminación automática de uno de los temas grandes y no pareció tener ningún efecto en las llamadas repetidas de Jobs::SyncTopicUserBookmarked sobre ese ID de tema.

Reduje SIDEKIQ_WORKERS a 2 y, poco después, la cola (con muchas cosas pendientes) se vació y ya no se está ejecutando Jobs::SyncTopicUserBookmarked:thinking:

Antes de intentar eso, capturé la siguiente consulta ejecutándose varias veces a la vez (usando el mismo topic id):

SELECT bookmarks.user_id, COUNT(*)
INTO TEMP TABLE tmp_sync_topic_user_bookmarks
FROM bookmarks
LEFT JOIN posts ON posts.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'Post'
LEFT JOIN topics ON (topics.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'Topic') OR
 (topics.id = posts.topic_id)
WHERE (topics.id = 51303 OR posts.topic_id = 51303)
AND posts.deleted_at IS NULL AND topics.deleted_at IS NULL
GROUP BY bookmarks.user_id;

UPDATE topic_users
SET bookmarked = true
FROM tmp_sync_topic_user_bookmarks
WHERE topic_users.user_id = tmp_sync_topic_user_bookmarks.user_id AND
  topic_users.topic_id = 51303 AND
  tmp_sync_topic_user_bookmarks.count > 0;

UPDATE topic_users
SET bookmarked = false
FROM tmp_sync_topic_user_bookmarks
WHERE topic_users.topic_id = 51303 AND
  topic_users.bookmarked = true AND
  topic_users.user_id NOT IN (
    SELECT tmp_sync_topic_user_bookmarks.user_id
    FROM tmp_sync_topic_user_bookmarks
  );

DROP TABLE tmp_sync_topic_user_bookmarks;

No está claro cómo PostgreSQL ejecuta múltiples sentencias en una sola consulta, pero si se ejecuta varias veces de forma concurrente, ¿podría causar un bucle de alguna manera?