E-Mail-Benachrichtigungen schlagen fehl, wenn doppelte Header vorhanden sind

Siehe Email notifications fail if duplicate headers exist - #14 by simonk für die Fehlerbeschreibung
Oben hinzugefügt von @pfaffman

Originaltext folgt

Hallo,

ich betreibe seit einigen Jahren eine eher kleine Discourse-Installation. Sie hat relativ wenig Traffic, daher hat es eine Weile gedauert, bis ich bemerkte, dass der Versand von E-Mails (Benachrichtigungen, Digests) vor einigen Monaten offensichtlich fehlgeschlagen ist. Die Untersuchung deutet auf das Upgrade auf 2.8.0.beta7 um den 22.10.2022 hin, zuvor waren wir auf 2.8.0.beta4. Zumindest habe ich seitdem keine E-Mail von dieser Installation über Beiträge oder Nachrichten erhalten.

Die E-Mails stapeln sich in Sidekiq mit einer Meldung, die ich nicht zuordnen kann und zu der ich auch nichts Passendes finde, wenn ich danach suche – es gab Berichte über undefined method-Meldungen, aber keine der Bedingungen passt auf meinen Fall. (Es ist kein TLS, es ist kein Timeout zum Mailserver, es ist nicht das Events-Plugin, und der Secure Media Fix sollte bereits vorhanden sein – außerdem waren die genauen Fehlermeldungen anders.)

Fehler in Sidekiq:

Wrapped NoMethodError: undefined method `value' for #<Array:0x00007f7fd5277d68> Did you mean? values_at

Der Teil nach #<Array: ist für jede gehaltene E-Mail unterschiedlich. Ich habe gestern Abend Discourse auf einer neuen VM neu installiert und aus einem frischen Backup wiederhergestellt – aber anscheinend wurde das E-Mail-Problem mit den Daten wiederhergestellt :thinking:

Da die Fehlerrate Ende Oktober zu steigen begann, bin ich ziemlich sicher, dass dies durch 2.8.0.beta7 eingeführt wurde:

Jede Hilfe oder jeder Hinweis zur weiteren Fehlersuche wird sehr geschätzt.

1 „Gefällt mir“

Haben Sie Plugins installiert? Wenn Sie nicht standardmäßige Plugins haben, sollten Sie diese entfernen.

Habe das bereits versucht, das Problem besteht weiterhin :frowning:

## Plugins go here
## see https://meta.discourse.org/t/19157 for details
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git

## Any custom commands to run after building

EDIT: Zur Info:

Vorgesehene Plugins:

root@discourse:/var/discourse# grep -B5 "git clone" containers/app.yml-with-plugins
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git
          - git clone https://github.com/discourse/discourse-spoiler-alert.git
          - git clone https://github.com/discourse/discourse-prometheus.git
          - git clone https://github.com/discourse/discourse-solved.git
          - git clone https://github.com/discourse/discourse-chat-integration.git
          - git clone https://github.com/discourse/discourse-voting.git
          - git clone https://github.com/discourse/discourse-checklist.git
          - git clone https://github.com/discourse/discourse-whos-online.git
          - git clone https://github.com/discourse/discourse-calendar.git
          - git clone https://github.com/discourse/discourse-affiliate.git
          - git clone https://github.com/discourse/discourse-reactions.git
          - git clone https://github.com/discourse/discourse-surveys.git

Die alte Installation hat:

root@discourse-old:/var/discourse# grep -B5 "git clone" containers/app.yml
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git
          - git clone https://github.com/discourse/discourse-spoiler-alert.git
          - git clone https://github.com/discourse/discourse-prometheus.git
          - git clone https://github.com/discourse/discourse-solved.git
          - git clone https://github.com/discourse/discourse-chat-integration.git
          - git clone https://github.com/discourse/discourse-voting.git
          - git clone https://github.com/discourse/discourse-checklist.git
          - git clone https://github.com/davidtaylorhq/discourse-whos-online.git

Ist dies eine Standardinstallation? Wenn Sie einen separaten Datencontainer haben, wurde dieser neu erstellt? Ist PostgreSQL auf dem neuesten Stand? (Obwohl ich glaube, dass es dafür immer noch eine Prüfung im Code gibt)

Ja, es ist eine Standardinstallation; soweit ich das beurteilen kann, läuft nur ein Container. (Neue VM hochfahren, DNS neu zuweisen, apt update, apt dist-upgrade, neu starten, git pull, ./discourse-setup, webbasierte Einrichtung, Backup hochladen, Backup wiederherstellen, E-Mail wieder aktivieren, Fehler erneut sehen.) Beachten Sie, dass die alte Installation in der Lage war, den Link zum Backup per E-Mail zu versenden, und das Senden von Test-E-Mails funktioniert in der neuen Installation immer noch – es scheinen nur E-Mails im Zusammenhang mit dem Posten fehlerhaft zu sein.

Genauer gesagt handelt es sich um eine minimale Debian 10-Installation, auf der ich Discourse installiert habe:

root@discourse:~# history
    1  apt update
    2  apt dist-upgrade
    3  reboot ; exit
    4  git clone https://github.com/discourse/discourse_docker.git /var/discourse
    5  apt install git rsync
    6  git clone https://github.com/discourse/discourse_docker.git /var/discourse
    7  cd /var/discourse
       [attach /dev/vdb, fdisk, mkfs.ext4, mount as /var/lib/docker]
   18  apt-get install git apt-transport-https ca-certificates curl gnupg2 software-properties-common -y
   19  df -h
   20  curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo \"$ID\")/gpg | apt-key add -
   21  add-apt-repository \"deb [arch=amd64] https://download.docker.com/linux/$(. /etc/os-release; echo \"$ID\") $(lsb_release -cs) stable\"
   22  apt-get update -y
   23  apt-get install docker-ce -y
   24  ./discourse-setup

Und ein Container:

root@discourse:~# docker ps
CONTAINER ID   IMAGE                 COMMAND        CREATED        STATUS        PORTS                                                                      NAMES
ac408a70305d   local_discourse/app   \"/sbin/boot\"   12 hours ago   Up 12 hours   0.0.0.0:80-\u003e80/tcp, :::80-\u003e80/tcp, 0.0.0.0:443-\u003e443/tcp, :::443-\u003e443/tcp   app

Bearbeiten:

root@discourse:~# apt update
Hit:1 https://download.docker.com/linux/debian buster InRelease
Hit:2 http://deb.debian.org/debian buster InRelease
Get:3 http://deb.debian.org/debian buster-updates InRelease [51,9 kB]
Get:4 http://security.debian.org/debian-security buster/updates InRelease [65,4 kB]
Fetched 117 kB in 2s (60,5 kB/s)    
Reading package lists... Done
Building dependency tree       
Reading state information... Done
All packages are up to date.

Die ersten Wiederherstellungen sind jedoch fehlgeschlagen. database_restorer.rb ist in restore_dump aufgrund duplizierter Links in post_id 3841 fehlgeschlagen. Ich habe diese Links in einem Beitrag aus dem Jahr 2017 durch einen Screenshot davon aus der alten Installation ersetzt und dann ein weiteres Backup erstellt; erst dann konnte ich das Backup auf der neuen Installation wiederherstellen. Da Sie PostgreSQL erwähnt haben, geschah dies während CREATE INDEX mit ERROR: could not create unique index \"unique_post_links\". Weitere Informationen: EXCEPTION: psql failed: DETAIL: Key (topic_id, post_id, url)=(1300, 3841, [redacted]) is duplicated.

Obwohl ich nicht glaube, dass dies direkt damit zusammenhängt, dachte ich, ich sollte es erwähnen.

Also, wenn niemand einen einfachen Weg kennt, das zu beheben, lassen Sie uns das richtig debuggen. Aber ich brauche Ihre Hilfe, da Discourse eine ziemlich komplexe Anwendung ist, die eine Reihe von Technologien verwendet, mit denen ich nicht vertraut bin. Also: Wie werden E-Mails an Sidekiq gesendet?

Welche Komponente von Discourse gibt Sitekiq eine Methode „value“?

Da E-Mail-Benachrichtigungen nach einem Upgrade nicht mehr funktionieren, ist Discourse leider ziemlich nutzlos. Anstatt sofortiger Aufmerksamkeit dauern Themen jetzt Tage, um Aufmerksamkeit zu erregen, wenn überhaupt, da die Leute im Jahr 2022 keine aktive Abfrage durchführen. Keine Benachrichtigung ⇒ nichts ist passiert ⇒ kein Grund, die Website zu überprüfen :frowning:

1 „Gefällt mir“

Das sieht nach einem beschädigten Index aus. Ich glaube nicht, dass ich das bei Postgres 13 gesehen habe. Es klingt, als hätten Sie diese auf einer alten Seite behoben und dann durch Sichern und Wiederherstellen auf einer neuen Seite aktualisiert?

Es sieht so aus, als hätte das Problem mit etwas im Code zu tun, das Benachrichtigungen sendet, aber es ist ein Problem mit Sidekiq.

Wie gesagt, die alte Seite läuft, ich habe ein Backup gemacht und das auf eine frische Installation gespielt, die Wiederherstellung schlug fehl. Ich habe den Beitrag, der als Schuldiger identifiziert wurde, so lange geändert, bis die Wiederherstellung auf der frischen Installation funktionierte. Nur um dann wieder/immer noch das Problem mit Sitekiq zu haben.

Die alte Seite läuft ebenfalls mit Postgres 13 (geht aber mehrere Jahre zurück, also hat sie höchstwahrscheinlich nicht mit dieser Version angefangen :slightly_smiling_face:)

root@discourse-old:/var/discourse# ./launcher enter app
x86_64 arch detected.
root@discourse-app:/var/www/discourse# psql --version
psql (PostgreSQL) 13.5 (Debian 13.5-1.pgdg110+1)

Laut diesem Schlusskommentar des Beitrags kann Discoures Datenbank beschädigt werden – und repariert werden.

Mit einem neuen Benutzer versucht, er erhält seine Registrierungs-E-Mail ordnungsgemäß. Aber Benachrichtigungen über Antworten auf seine Beiträge, nein; Sidekiq schlägt fehl.

Für mich bedeutet das also, dass Discourse einige fehlerhafte Informationen an Sidekiq weitergibt, wenn es ihm anweist, Benachrichtigungen zu senden (im Gegensatz zur Registrierungs-E-Mail). Wie kann man das weiter debuggen?

OK, wenn die Indizes repariert sind, dann deutet das für mich darauf hin, dass etwas mit einem Array anstelle eines Modells aufgerufen wird, das value hat. Das Problem liegt nicht bei Sidekiq an sich, sondern bei der Funktion, die Sidekiq zum Aufruf bringt.

Es klingt also, als ob etwas aufgerufen wird, das ein Array anstelle eines einzelnen Elements zurückgibt, aber ich kann nicht erraten, was. Ich denke, Sie müssen in /var/discourse/shared/standalone/logs/rails/production.log (oder etwas sehr Ähnlichem, falls meine Finger oder mein Gedächtnis versagen) nachsehen. Dann können Sie in diesen Protokollen nach diesem Fehler suchen (oder ihn erneut auslösen, damit er am Ende der Datei steht). Dort sollten Sie weitere Informationen darüber erhalten, was fehlschlägt.

Danke, aber das sagt nicht wirklich viel aus:

Started POST "/sidekiq/retries" for 185.39.142.187 at 2022-04-11 16:31:35 +0000
start
Started GET "/sidekiq/retries" for 185.39.142.187 at 2022-04-11 16:31:35 +0000
  Rendered email/notification.html.erb (Duration: 42.8ms | Allocations: 4323)
  Rendered layouts/email_template.html.erb (Duration: 0.3ms | Allocations: 29)
Job exception: undefined method `value' for #<Array:0x00007ff393af6c78>
Did you mean?  values_at

fail

shared/standalone/log/rails/production_errors.log ist leer.

Wird der Fehler unter Admin -\u003e Protokolle -\u003e Fehlerprotokolle angezeigt? Wenn ja, können Sie eine vollständige Stacktrace erhalten, die möglicherweise hilfreich ist.

1 „Gefällt mir“

Oh, schön – ja, das tut es:

Wenn ich das richtig verstehe,

 433    def header_value(name)
 434      header = @message.header[name]
 435      return nil unless header
*436      header.value
 437    end

ist – im Discource-Code? – dort, wo Sidekiq aussteigt?

Das wird aufgerufen von …

 228      MessageBuilder.custom_headers(SiteSetting.email_custom_headers).each do |key, _|
*229        value = header_value(key)
 230
 231        # Remove Auto-Submitted header for group private message emails, it does
 232        # not make sense there and may hurt deliverability.

Also könnte es ein benutzerdefinierter Header sein?

Ich habe tatsächlich einen Eintrag dort:

Screenshot 2022-04-12 at 11-27-31 Administration - Freifunk Kreis GT

Ich habe dies auf die Standardwerte zurückgesetzt und … tatsächlich scheint es, dass E-Mail-Benachrichtigungen wieder versendet werden, wie von Lesern bestätigt.

Danke!

Eine Frage bleibt jedoch: Warum verursacht »Auto-Submitted: auto-generated|Precedence: bulk« diesen Fehler? Es besagt, dass benutzerdefinierte Header durch »|« getrennt werden sollen.

1 „Gefällt mir“

(Haftungsausschluss: kein Ruby-Programmierer)

Ich halte das für ein besonders unangenehmes Verhalten in der Mail-Bibliothek, die Discourse verwendet. Hier ist die Funktion header_value:

Soweit ich das beurteilen kann, ruft @message.header[name] diese Methode auf:

https://www.rubydoc.info/github/mikel/mail/Mail%2FHeader:[]

Gemäß RFC können viele Felder mehrfach vorkommen. Wir geben einen String des Werts zurück, wenn nur ein Header vorhanden ist, oder wenn mehr als ein übereinstimmender Header vorhanden ist, geben wir ein Array von Werten zurück, in der Reihenfolge, in der sie im Header von oben nach unten erscheinen.

Discourse setzt automatisch einen Precedence-Header. Da Sie über die Einstellung email_custom_headers einen weiteren hinzufügen, gibt es nun zwei Precedence-Header, und @message.header[\"Precedence\"] gibt ein Array anstelle eines Strings zurück.

Ich glaube, dieser Fehler wird immer dann ausgelöst, wenn email_custom_headers einen Header enthält, der bereits im Nachrichtenobjekt vorhanden ist.

5 „Gefällt mir“

Das sieht für mich so aus, als ob das passiert (ich habe vorgeschlagen, dass etwas ein Array und kein einzelnes Element ist, aber ich konnte mir nicht vorstellen, wie das wahr sein könnte) und ein Fehler ist.

Ich werde den Titel und die Kategorie dieses Themas ändern.

3 „Gefällt mir“

Ich habe heute einen Fix dafür zusammengeführt. Wenn wir einen doppelten Header erkennen, verwenden wir einfach den in Discourse Core definierten anstelle des benutzerdefinierten aus den Site-Einstellungen:

4 „Gefällt mir“

Dieses Thema wurde nach 2 Tagen automatisch geschlossen. Neue Antworten sind nicht mehr möglich.