Discourse 2026.10.0-latest.1 / Sidekiq 7.3.10 / Ruby 4.0.9
Resumo
Desde a atualização de um fórum auto-hospedado do Discourse 2026.2.0-latest (Ruby 3.3.8) para o 2026.10.0-latest.1 (Ruby 4.0.9, Rails 8.1.4, Sidekiq 7.3.10) em 26/10/2026, trabalhos enfileirados com Jobs.enqueue_in estão sendo perdidos intermitentemente e silenciosamente: o trabalho desaparece do conjunto ordenado schedule no momento de sua execução programada, mas o método perform nunca é executado. Não há nova tentativa, não há trabalho morto, nenhuma exceção registrada (usamos Logster::RedisStore, portanto exceções engolidas são visíveis — não há nenhuma) e stat:failed permanece em 0. Taxa de perda observada em 9 ocorrências controladas/reais: 4 perdidos / 5 executados (~40 %).
Ambiente
- Instalação oficial via docker (
./launcher rebuild), único site - Discourse
2026.10.0-latest.1, imagemdiscourse/base:2.0.20261026-0138 - Ruby 4.0.9 (2026-10-23), Rails 8.1.4, Sidekiq 7.3.10
UNICORN_SIDEKIQS=1(Sidekiq supervisionado porDemon::Sidekiq, bifurcado pelo pitchfork)- Estado do Sidekiq em um banco de dados Redis dedicado (
Discourse.sidekiq_redis_config), separado do Redis do Discourse - Processo do Sidekiq saudável durante todas as observações: 0 reinicializações,
[0 de 5 ocupados], filas vazias,retry = 0,dead = 0,stat:failed = 0 - Sem OOM, sem eventos no dmesg, sem reinicializações do contêiner
Observações (30/10/2026, caso real + experimentos controlados)
O trabalho afetado é Jobs::NotifyMailingListSubscribers, enfileirado com Jobs.enqueue_in(SiteSetting.email_time_window_mins.minutes, ...) (600 s) → conjunto ordenado schedule com score = momento da execução.
| Momento da execução (UTC) | Trabalho | Resultado |
|---|---|---|
| 15:33:05 | real (post 282) | perdido — desapareceu de schedule, nunca executado |
| 15:50:10 | controle (post_id 999999 → retorno silencioso antecipado) | executado (+1 stat:processed ~8 s após o momento programado) |
| 16:04:18 | real (post 283) | executado (erros SMTP gravados, ver abaixo) |
| 16:21:44 | real ×2 + controle | todos executados |
| 17:34:39 | real ×2 | perdidos ×2 |
| 17:42:39 | controle | executado (+1, 11 s após o momento programado) |
| 17:55:59 | real | perdido |
Evidências reunidas para cada trabalho “perdido”:
zrange schedulenão contém mais a carga útil (ozremocorreu), e ela não está presente nem emretry, nem emdead, nem em qualquer fila (queue:lowetc. todas com 0), nem atribuída astat:processed.- Um observador
pg_stat_activityamostrando a cada 300 ms durante a janela de execução programada não registrou nenhuma consulta SQL vinda da conexão do Sidekiq — nem mesmo a consulta inicialSELECT ... FROM postsqueexecuterealiza primeiro. - O
Logster::RedisStore(__LOGSTER__MAP) não contém novas entradas para esses trabalhos, enquanto as entradas SÃO gravadas para as execuções executadas (falhas SMTP de um problema diferente e não relacionado que corrigimos em paralelo). - O proctitle do Sidekiq permanece
[0 de 5 ocupados]; sem reinicialização do Sidekiq (mesmo PID desde a inicialização), sem OOM. - A contagem de
SkippedEmailLogpermaneceu inalterada para os trabalhos perdidos (as execuções executadas e com falha realmente gravam linhas lá).
As execuções “executadas” são positivamente confirmadas: elas produziram entradas de erro SMTP por usuário (capturadas em SkippedEmailLog.custom_reason), portanto, a classe do trabalho e a forma da carga útil são idênticas entre as ocorrências perdidas e executadas (mesma classe, mesma fila low, apenas post_id difere).
A instalação anterior (Discourse 2026.2.0-latest, Ruby 3.3.8) não exibiu esse comportamento: os mesmos trabalhos de lista de e-mail agendados foram entregues de forma confiável em 01/10/2026 e 21/10/2026 (verificado via EmailLog + filas do MTA a jusante).
Mitigação aplicada
Definimos email_time_window_mins = 0 para este site para que enqueue_in(0) ignore a chave at e envie o trabalho diretamente para sua fila (client_push sem at), evitando completamente o poller agendado. Após essa alteração, todas as 6 linhas esperadas de EmailLog foram criadas imediatamente e os e-mails foram aceitos pelo MTA a jusante.
Concessão aceita: as notificações de listas de discussão são agora enviadas imediatamente em vez de serem agrupadas com +10 min.
Perguntas
- Esta é uma regressão conhecida na combinação 2026.10 / Sidekiq 7.3.10 (ou em
Demon::Sidekiq/ o poller agendado sob Ruby 4.0)? - Quais diagnósticos adicionais vocês gostariam que capturássemos na próxima ocorrência (por exemplo, habilitar a instrumentação de trabalhos
DISCOURSE_LOG_SIDEKIQ=1, backtraces de exceções do Sidekiq, dumps de threads do poller)?