فشل إشعارات البريد الإلكتروني في حالة وجود رؤوس مكررة

انظر Email notifications fail if duplicate headers exist - #14 by simonk لوصف الخطأ
أضاف @pfaffman أعلاه
النص الأصلي يتبع

مرحباً،

أقوم بتشغيل تثبيت Discourse صغير نسبيًا منذ سنوات. إنه ذو حركة مرور منخفضة إلى حد ما، لذلك استغرق الأمر بعض الوقت لملاحظة أن إرسال رسائل البريد الإلكتروني (الإشعارات، الملخصات) قد فشل بوضوح منذ بضعة أشهر. تشير التحقيقات إلى الترقية إلى 2.8.0.beta7 حوالي 2022-10-22، سابقًا كنا على 2.8.0.beta4. على الأقل لم أتلق أي بريد إلكتروني من هذا التثبيت حول المشاركات أو الرسائل.

تتكدس رسائل البريد الإلكتروني في Sidekiq، مع رسالة لا يمكنني ربطها، ولا أجد أي شيء مناسب عند البحث عنها - كانت هناك تقارير عن رسائل undefined method، ولكن لا تتطابق أي من الشروط مع حالتي. (إنه ليس TLS، ولا يوجد مهلة لخادم البريد، ولا توجد إضافة الأحداث، ويجب أن يكون إصلاح الوسائط الآمنة قد تم بالفعل - بالإضافة إلى ذلك، كانت رسائل الخطأ الدقيقة مختلفة.)

خطأ في Sidekiq:

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

الجزء الذي يلي #<Array: مختلف لكل بريد إلكتروني محتفظ به. قمت بإعادة تثبيت Discourse إلى جهاز افتراضي جديد الليلة الماضية واستعدت من نسخة احتياطية حديثة - ولكن يبدو أن مشكلة البريد الإلكتروني قد تم استعادتها مع البيانات :thinking:

نظرًا لأن معدل الخطأ بدأ في الارتفاع في أواخر أكتوبر، فأنا متأكد تمامًا من أن هذا تم تقديمه بواسطة 2.8.0.beta7:

أي مساعدة، أو تلميح لتصحيح المشكلة بشكل أكبر، محل تقدير كبير.

إعجاب واحد (1)

هل لديك أي إضافات مثبتة؟ إذا كانت لديك إضافات غير قياسية، فيجب عليك إزالتها.

لقد جربت هذا بالفعل، ولا تزال المشكلة قائمة :frowning:

## يتم وضع المكونات الإضافية هنا
## انظر https://meta.discourse.org/t/19157 للتفاصيل
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git

## أي أوامر مخصصة للتنفيذ بعد البناء

تحرير: للعلم:

المكونات الإضافية المقصودة:

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

التثبيت القديم يحتوي على:

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

هل هذا تثبيت قياسي؟ إذا كان لديك حاوية بيانات منفصلة، فهل أعيد بناؤها؟ هل تم تحديث PostgreSQL؟ (على الرغم من أنني أعتقد أنه لا يزال هناك تحقق من هذا في الكود)

نعم، إنها تثبيت قياسي؛ على حد علمي، هناك حاوية واحدة فقط قيد التشغيل. (قم بتشغيل جهاز افتراضي جديد، وأعد توجيه نظام أسماء النطاقات، وقم بتحديث apt، وقم بترقية apt، وأعد التشغيل، وقم بسحب git، وقم بتشغيل ./discourse-setup، وقم بإعداد الواجهة المستندة إلى الويب، وقم بتحميل النسخ الاحتياطي، واستعادة النسخ الاحتياطي، وأعد تمكين البريد، وشاهد الأخطاء مرة أخرى.) لاحظ أن التثبيت القديم كان قادرًا على إرسال رابط النسخ الاحتياطي عبر البريد الإلكتروني، ولا يزال إرسال رسائل البريد الإلكتروني التجريبية يعمل في التثبيت الجديد — يبدو أن رسائل البريد الإلكتروني المتعلقة بالنشر فقط هي التي تفشل.

لتكون أكثر دقة، إنها تثبيت Debian 10 بسيط، قمت بتثبيت discourse عليه:

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

وحاوية واحدة:

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->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp   app

تعديل:

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.

في الواقع، فشلت عمليات الاستعادة الأولى. فشل database_restorer.rb في restore_dump بسبب روابط مكررة في post_id 3841. انتهى بي الأمر باستبدال هذه الروابط في منشور من عام 2017 لقطة شاشة لها من التثبيت القديم وقمت بعمل نسخة احتياطية أخرى؛ فقط بعد ذلك تمكنت من استعادة النسخة الاحتياطية على التثبيت الجديد. بما أنك ذكرت postgres، فقد حدث هذا أثناء CREATE INDEX مع ERROR: could not create unique index \"unique_post_links\". مزيد من المعلومات: EXCEPTION: psql failed: DETAIL: Key (topic_id, post_id, url)=(1300, 3841, [redacted]) is duplicated.

بينما لا أعتقد أن هذا مرتبط بشكل مباشر، فقد اعتقدت أنه يجب علي ذكره.

إذن، إذا لم يعرف أحد طريقة سهلة لإصلاح ذلك، فلنقم بتصحيح الأخطاء بشكل صحيح. لكنني بحاجة إلى مساعدتكم، حيث أن Discourse تطبيق معقد إلى حد ما يستخدم مجموعة من التقنيات التي لست على دراية بها. إذن: كيف يتم إرسال رسائل البريد الإلكتروني إلى Sidekiq؟

ما هو المكون في Discourse الذي يعطي Sitekiq طريقة “value”؟

مع توقف إشعارات البريد الإلكتروني عن العمل بعد الترقية، فإن Discourse عديم الفائدة للأسف الآن. بدلاً من الاهتمام الفوري، تستغرق المواضيع الآن أيامًا للحصول على الاهتمام، إن وجدت، حيث لا يقوم الأشخاص بالاستطلاع النشط في عام 2022. لا يوجد إشعار ⇒ لم يحدث شيء ⇒ لا حاجة للتحقق من الموقع :frowning:

إعجاب واحد (1)

يبدو هذا كفهرس تالف. لا أعتقد أنني رأيت هذا على postgres 13. يبدو أنك قمت بإصلاح تلك الموجودة في موقع قديم ثم قمت بالترقية عن طريق النسخ الاحتياطي والاستعادة إلى موقع جديد؟

يبدو أن المشكلة تتعلق بشيء في الكود الذي يرسل الإشعارات، ولكنه مشكلة في sidekiq.

كما قلت، الموقع القديم يعمل، وقمت بعمل نسخة احتياطية ووضعتها على تثبيت جديد، فشلت الاستعادة. قمت بتعديل المنشور المشار إليه على أنه المذنب حتى نجحت الاستعادة على التثبيت الجديد. فقط لأرى أن لدي المشكلة مع Sitekiq مرة أخرى/لا تزال.

الموقع القديم يعمل بنظام postgres 13 أيضًا (ولكنه يعود لعدة سنوات، لذا من المحتمل جدًا أنه لم يبدأ بهذا الإصدار :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)

إذًا، وفقًا لـ تعليقات إغلاق هذا المنشور، يمكن أن يتلف قاعدة بيانات Discourse - ويتم إصلاحها.

جربت مع مستخدم جديد، يحصل على بريد التسجيل الخاص به بشكل صحيح. ولكن الإشعارات حول الردود على منشوراته، لا؛ Sidekiq يخرج بخطأ.

إذًا، بالنسبة لي هذا يعني أن Discourse يعطي بعض المعلومات الخاطئة لـ Sidekiq عندما يوجهه لإرسال الإشعارات (على عكس بريد التسجيل). كيف يمكنني تصحيح المزيد من الأخطاء؟

حسنًا، إذا تم إصلاح الفهارس، فهذا يشير لي إلى أن شيئًا ما يتم استدعاؤه بمصفوفة بدلاً من نموذج يحتوي على value. المشكلة ليست مع sidekiq، بحد ذاتها، ولكن مع الوظيفة التي يتسبب sidekiq في استدعائها.

لذا يبدو أن شيئًا ما يتم استدعاؤه ويعيد مصفوفة بدلاً من عنصر واحد، ولكن لا يمكنني تخمين ما هو. أعتقد أنك ستحتاج إلى النظر في /var/discourse/shared/standalone/logs/rails/production.log (أو شيء مشابه جدًا لذلك إذا كانت أصابعي أو ذاكرتي تخونني). ثم يمكنك البحث في تلك السجلات عن هذا الخطأ (أو التسبب في حدوثه مرة أخرى حتى يكون في نهاية الملف). يجب أن تحصل على مزيد من المعلومات حول ما يفشل هناك.

شكرًا، لكنه لا يخبر الكثير حقًا:

بدأ POST "/sidekiq/retries" لـ 185.39.142.187 في 2022-04-11 16:31:35 +0000
البدء
بدأ GET "/sidekiq/retries" لـ 185.39.142.187 في 2022-04-11 16:31:35 +0000
  تم عرض email/notification.html.erb (المدة: 42.8 مللي ثانية | التخصيصات: 4323)
  تم عرض layouts/email_template.html.erb (المدة: 0.3 مللي ثانية | التخصيصات: 29)
استثناء المهمة: طريقة غير معرفة `value` لـ #<Array:0x00007ff393af6c78>
هل قصدت؟ values_at

فشل

shared/standalone/log/rails/production_errors.log فارغ.

هل يظهر الخطأ في المسؤول → السجلات → سجلات الأخطاء؟ إذا كان الأمر كذلك، يمكنك الحصول على تتبع كامل للمكدس قد يساعد.

إعجاب واحد (1)

أوه، لطيف — نعم، يبدو ذلك:

إذًا، إذا فهمت هذا بشكل صحيح،

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

هو – في كود Discourse؟ – المكان الذي يتعثر فيه Sidekiq؟

يتم استدعاء هذا من…

 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.

إذًا يمكن أن يكون رأسًا مخصصًا؟

بالفعل لدي إدخال هناك:

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

لقد أعدت تعيين هذا إلى الإعدادات الافتراضية، و… في الواقع يبدو أن إشعارات البريد الإلكتروني يتم إرسالها مرة أخرى، كما تحقق القراء.

شكرًا!

يبقى سؤال واحد، مع ذلك: لماذا يتسبب »Auto-Submitted: auto-generated|Precedence: bulk« في هذا الفشل؟ يذكر أن الرؤوس المخصصة يجب فصلها بـ »|«.

إعجاب واحد (1)

(إخلاء مسؤولية: لست مبرمج روبي)

أعتقد أن هذا سلوك بغيض بشكل خاص في مكتبة البريد التي يستخدمها ديسكورس. إليك دالة header_value:

على حد علمي، فإن @message.header[name] تستدعي هذه الطريقة:

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

وفقًا لـ RFC، يمكن أن تظهر العديد من الحقول أكثر من مرة، وسنعيد سلسلة نصية للقيمة إذا كان هناك رأس واحد فقط، أو إذا كان هناك أكثر من رأس مطابق، فسنعيد مصفوفة من القيم بالترتيب الذي تظهر به في الرأس مرتبة من الأعلى إلى الأسفل.

يقوم ديسكورس بتعيين رأس Precedence تلقائيًا، لذلك نظرًا لأنك تضيف واحدًا أيضًا عبر إعداد email_custom_headers، فهناك الآن رأسان Precedence، ويعيد @message.header["Precedence"] مصفوفة بدلاً من سلسلة نصية.

أعتقد أن هذه المشكلة سيتم تفعيلها في أي وقت يحتوي فيه email_custom_headers على رأس موجود بالفعل في كائن الرسالة.

5 إعجابات

يبدو لي هذا ما يحدث (اقترحت أن شيئًا ما كان مصفوفة بدلاً من عنصر واحد، لكن لم أستطع تخيل كيف يمكن أن يكون ذلك صحيحًا) وهو خطأ.\n\nسأقوم بتغيير عنوان هذا الموضوع وفئته.

3 إعجابات

لقد قمت بدمج إصلاح لهذا اليوم، إذا اكتشفنا رأسًا مكررًا، فإننا نستخدم فقط الرأس المحدد في Discourse core بدلاً من الرأس المخصص من إعدادات الموقع:

4 إعجابات

تم إغلاق هذا الموضوع تلقائيًا بعد يومين. لم يعد يُسمح بالردود الجديدة.