Discourse 2026.10.0-latest.1 / Sidekiq 7.3.10 / Ruby 4.0.9
Zusammenfassung
Seit dem Upgrade eines selbst gehosteten Forums von Discourse 2026.2.0-latest (Ruby 3.3.8) auf 2026.10.0-latest.1 (Ruby 4.0.9, Rails 8.1.4, Sidekiq 7.3.10) am 26.10.2026 werden Jobs, die mit Jobs.enqueue_in in die Warteschlange gestellt wurden, intermittierend und stillschweigend verworfen: Der Job verschwindet zur Fälligkeit aus dem schedule-zset, aber perform wird nie ausgeführt. Es gibt keinen Retry, keinen Dead Job und keine protokollierte Ausnahme (wir verwenden Logster::RedisStore, sodass verschluckte Ausnahmen sichtbar wären – es gibt jedoch keine), und stat:failed bleibt bei 0. Die beobachtete Verlustrate über 9 kontrollierte/reale Vorfälle: 4 verloren / 5 ausgeführt (~40 %).
Umgebung
- Offizielle Docker-Installation (
./launcher rebuild), einzelne Site - Discourse
2026.10.0-latest.1, Imagediscourse/base:2.0.20261026-0138 - Ruby 4.0.9 (23.10.2026), Rails 8.1.4, Sidekiq 7.3.10
UNICORN_SIDEKIQS=1(Sidekiq wird vonDemon::Sidekiqüberwacht, forked durch pitchfork)- Sidekiq-Zustand in einer dedizierten Redis-Datenbank (
Discourse.sidekiq_redis_config), getrennt vom Discourse-Redis - Sidekiq-Prozess während aller Beobachtungen gesund: 0 Neustarts,
[0 of 5 busy], Warteschlangen leer,retry = 0,dead = 0,stat:failed = 0 - Kein OOM, keine dmesg-Ereignisse, keine Container-Neustarts
Beobachtungen (30.10.2026, realer Fall + kontrollierte Experimente)
Der betroffene Job ist Jobs::NotifyMailingListSubscribers, eingeplant mit Jobs.enqueue_in(SiteSetting.email_time_window_mins.minutes, ...) (600 s) → schedule-zset mit Score = Fälligkeitszeit.
| Fälligkeitszeit (UTC) | Job | Ergebnis |
|---|---|---|
| 15:33:05 | real (Post 282) | verloren – aus schedule verschwunden, nie ausgeführt |
| 15:50:10 | Kontrolle (post_id 999999 → stiller Early-Return) | ausgeführt (+1 stat:processed ~8 s nach Fälligkeit) |
| 16:04:18 | real (Post 283) | ausgeführt (SMTP-Fehler geschrieben, siehe unten) |
| 16:21:44 | real ×2 + Kontrolle | alle ausgeführt |
| 17:34:39 | real ×2 | verloren ×2 |
| 17:42:39 | Kontrolle | ausgeführt (+1, 11 s nach Fälligkeit) |
| 17:55:59 | real | verloren |
Zusammengetragene Hinweise für jeden “verlorenen” Job:
zrange scheduleenthält die Payload nicht mehr (derzremhat stattgefunden), und sie ist weder inretry, noch indead, noch in einer Warteschlange (queue:lowusw. alle 0), noch in derstat:processed-Attribution vorhanden.- Ein
pg_stat_activity-Watcher, der alle 300 ms im Fälligkeitsfenster abfragte, zeichnete null SQL von der Sidekiq-Verbindung auf – nicht einmal die anfänglicheSELECT ... FROM posts-Abfrage, dieexecutezuerst durchführt. Logster::RedisStore(__LOGSTER__MAP) enthält keinen neuen Eintrag für diese Jobs, während Einträge für die ausgeführten Läufe geschrieben werden (SMTP-Fehler eines anderen, unrelateden Problems, das wir parallel behoben haben).- Sidekiq-Proctitle bleibt bei
[0 of 5 busy]; kein Sidekiq-Neustart (gleiche PID seit Boot), kein OOM. - Die Anzahl der
SkippedEmailLog-Einträge hat sich für verlorene Jobs nicht geändert (die ausgeführten und fehlschlagenden Läufe schreiben dort Zeilen).
Die “ausgeführten” Läufe wurden positiv bestätigt: Sie erzeugten pro Nutzer SMTP-Fehlereinträge (erfasst in SkippedEmailLog.custom_reason), sodass die Job-Klasse und die Payload-Struktur zwischen verlorenen und ausgeführten Vorkommen identisch sind (gleiche Klasse, gleiche Warteschlange low, nur post_id unterscheidet sich).
Die vorherige Installation (Discourse 2026.2.0-latest, Ruby 3.3.8) wies dieses Verhalten nicht auf: dieselben verzögerten Mailing-List-Jobs wurden am 01.10.2026 und 21.10.2026 zuverlässig zugestellt (verifiziert über EmailLog + Downstream-MTA-Warteschlangen).
Angewandte Abschwächung
Wir haben email_time_window_mins = 0 für diese Site gesetzt, sodass enqueue_in(0) den at-Key überspringt und den Job direkt in die Warteschlange pusht (client_push ohne at), wodurch der geplante Poller komplett umgangen wird. Nach dieser Änderung wurden alle 6 erwarteten EmailLog-Zeilen sofort erstellt und die E-Mails vom Downstream-MTA akzeptiert.
Akzeptierter Trade-off: Mailing-List-Benachrichtigungen werden nun sofort gesendet, anstatt gebündelt mit +10 Minuten Verzögerung.
Fragen
- Ist dies eine bekannte Regression in der Kombination 2026.10 / Sidekiq 7.3.10 (oder in
Demon::Sidekiq/ dem geplanten Poller unter Ruby 4.0)? - Welche zusätzlichen Diagnosen sollten wir beim nächsten Auftreten erfassen (z. B. Aktivierung der
DISCOURSE_LOG_SIDEKIQ=1Job-Instrumentierung, Sidekiq-Ausnahme-Backtraces, Poller-Thread-Dumps)?