2.7.0.beta2 فشل الترقية مع خطأ: مفتاح مكرر

كنت أقوم بالترقية من الإصدار 2.7.0.beta1 وحصلت على رسالة الخطأ التالية:

2021-01-22 20:16:22.015 UTC [4055] discourse@discourse LOG:  duration: 75335.241 ms  statement: UPDATE notifications SET processed = true
2021-01-22 20:16:23.792 UTC [4055] discourse@discourse LOG:  duration: 1776.591 ms  statement: ALTER TABLE "notifications" ALTER COLUMN "processed" SET NOT NULL
2021-01-22 20:16:25.198 UTC [4055] discourse@discourse LOG:  duration: 1323.298 ms  statement: CREATE  INDEX  "index_notifications_on_processed" ON "notifications"  ("processed")
2021-01-22 20:16:25.458 UTC [4055] discourse@discourse LOG:  duration: 241.063 ms  statement: CREATE TABLE "user_notification_schedules" ("id" bigserial primary key, "user_id" integer NOT NULL, "enabled" boolean DEFAULT FALSE NOT NULL, "day_0_start_time" integer NOT NULL, "day_0_end_time" integer NOT NULL, "day_1_start_time" integer NOT NULL, "day_1_end_time" integer NOT NULL, "day_2_start_time" integer NOT NULL, "day_2_end_time" integer NOT NULL, "day_3_start_time" integer NOT NULL, "day_3_end_time" integer NOT NULL, "day_4_start_time" integer NOT NULL, "day_4_end_time" integer NOT NULL, "day_5_start_time" integer NOT NULL, "day_5_end_time" integer NOT NULL, "day_6_start_time" integer NOT NULL, "day_6_end_time" integer NOT NULL)
2021-01-22 20:16:25.560 UTC [4055] discourse@discourse LOG:  duration: 100.868 ms  statement: CREATE  INDEX  "index_user_notification_schedules_on_user_id" ON "user_notification_schedules"  ("user_id")
2021-01-22 20:16:25.782 UTC [4055] discourse@discourse LOG:  duration: 142.180 ms  statement: CREATE  INDEX  "index_do_not_disturb_timings_on_scheduled" ON "do_not_disturb_timings"  ("scheduled")
2021-01-22 20:16:26.414 UTC [4055] discourse@discourse LOG:  duration: 361.514 ms  statement: UPDATE users
	SET locale = 'en_GB'
	WHERE locale = 'en'
	
2021-01-22 20:16:26.656 UTC [4055] discourse@discourse LOG:  duration: 132.778 ms  statement: UPDATE theme_translation_overrides
	SET locale = 'en_GB'
	WHERE locale = 'en'
	
2021-01-22 20:16:42.745 UTC [4055] discourse@discourse ERROR:  duplicate key value violates unique constraint "index_users_on_username"
2021-01-22 20:16:42.745 UTC [4055] discourse@discourse DETAIL:  Key (username)=(DaveW) already exists.
2021-01-22 20:16:42.745 UTC [4055] discourse@discourse STATEMENT:  UPDATE users
	SET locale = 'en'
	WHERE locale = 'en_US'
	
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:

PG::UniqueViolation: ERROR:  duplicate key value violates unique constraint "index_users_on_username"
DETAIL:  Key (username)=(DaveW) already exists.

ثم، في نهاية المخرجات:

I, [2021-01-22T20:16:42.805286 #1] INFO -- : Terminating async processes

I, [2021-01-22T20:16:42.805333 #1] INFO -- : Sending INT to HOME=/var/lib/postgresql USER=postgres exec chpst -u postgres:postgres:ssl-cert -U postgres:postgres:ssl-cert /usr/lib/postgresql/13/bin/postmaster -D /etc/postgresql/13/main pid: 49

I, [2021-01-22T20:16:42.805381 #1] INFO -- : Sending TERM to exec chpst -u redis -U redis /usr/bin/redis-server /etc/redis/redis.conf pid: 166

166:signal-handler (1611346602) Received SIGTERM scheduling shutdown...

2021-01-22 20:16:42.805 UTC [49] LOG: received fast shutdown request

2021-01-22 20:16:42.835 UTC [49] LOG: aborting any active transactions

2021-01-22 20:16:42.857 UTC [49] LOG: background worker "logical replication launcher" (PID 58) exited with exit code 1

166:M 22 Jan 2021 20:16:42.876 # User requested shutdown...

166:M 22 Jan 2021 20:16:42.876 * Saving the final RDB snapshot before exiting.

166:M 22 Jan 2021 20:16:44.758 * DB saved on disk

166:M 22 Jan 2021 20:16:44.758 # Redis is now ready to exit, bye bye...

2021-01-22 20:16:45.563 UTC [53] LOG: shutting down

I, [2021-01-22T20:16:52.806177 #1] INFO -- : HOME=/var/lib/postgresql USER=postgres exec chpst -u postgres:postgres:ssl-cert -U postgres:postgres:ssl-cert /usr/lib/postgresql/13/bin/postmaster -D /etc/postgresql/13/main pid:49 did not terminate cleanly, forcing termination!

FAILED

--------------------

Pups::ExecError: cd /var/www/discourse && su discourse -c 'bundle exec rake db:migrate' failed with return #<Process::Status: pid 4032 exit 1>

Location of failure: /pups/lib/pups/exec_command.rb:112:in `spawn'

exec failed with the params {"cd"=>"$home", "hook"=>"db_migrate", "cmd"=>["su discourse -c 'bundle exec rake db:migrate'"]}

d627ad17d1f22d839a7dc8099878e6272eb3ea1772539f6628e2a23dd830aca2

** FAILED TO BOOTSTRAP ** please scroll up and look for earlier error messages, there may be more than one.

./discourse-doctor may help diagnose the problem.

لا أدري كيف يمكن أن يكون هناك حسابان بنفس اسم المستخدم.

موقعنا معطل تمامًا. ماذا أفعل الآن؟

شكرًا،
غونار

إعجابَين (2)

أعتقد أنه يمكنك إعادة تشغيل الموقع باستخدام ./launcher start app

ثم استكشف طرقًا لحذف النسخة المكررة:

و

5 إعجابات

معلومات إضافية ربما يجب أن أقدمها:

  • هذا تثبيت لحاوية واحدة.
  • اكتمل إعادة البناء الأول دون أي أخطاء. حدث هذا الخطأ أثناء تشغيل إعادة البناء الثانية، بعد اكتمال إعادة البناء الأولى بنجاح.

شكرًا لك،
غونار

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

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

cd /var/discourse
git pull
 ./launcher rebuild app

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

جرّب هذا.

ابحث في المنتدى عن الأخطاء التي نشرتها لترى مختلف الإصلاحات التي نجحت مع آخرين.

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

تمت إعادة تشغيل الموقع بنجاح عن طريق إعادة تسمية postgres_data_old إلى postgres_data ثم تشغيل ./launcher start app لبدء الصورة القديمة.

لذا، عدت إلى نقطة الصفر، لكن على الأقل الموقع يعمل الآن.

حاولت العثور على المفتاح المكرر عن طريق إدخال الأمر التالي:

select * from users WHERE username = 'DaveW';

(كان username = DaveW هو المفتاح المسبب للمشكلة كما هو موضح في رسالة الخطأ في منشوري الأول في هذا الموضوع.)

أرجع الأمر بصفحة واحدة فقط، مستخدم واحد. ما الذي فاتني؟

شكرًا،
غونار

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

لديك بالفعل نسختان، ربما تختلفان في استخدام الأحرف الكبيرة في قاعدة البيانات:

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

هل زرت موقعي؟ :wink:

أفهم ما تقصده؛ فعندما أبحث في واجهة المستخدم الرسومية، أرى بالفعل حسابين. ومع ذلك، عندما أضغط على كليهما بصفتي مسؤولًا وأفتح صفحة التفاصيل، يبدو أنهما ينتميان إلى نفس المستخدم. لا أستطيع العثور على أي تفصيل واحد يختلف بينهما. بشكل أساسي، بغض النظر عن أي منهما أضغط عليه، أحصل على بيانات الحساب الثاني، وهو الذي يحتوي على الاسم الكامل المدخل.

بما أن هذا المستخدم لم ينشر قط ولم يزُر الموقع منذ فترة طويلة، فقد قمت بحذف الحساب من واجهة المستخدم الرسومية.

من المثير للاهتمام أنني ما زلت أملك الحساب الآخر، وهو الأول في قائمتك، والذي لا يحتوي على اسم كامل. ولكن الآن، إذا نقرت على هذا المستخدم، لا يحدث شيء. يمكنني رؤية نافذة حوار تحاول الفتح ثم تغلق على الفور.

عند البحث مباشرة في قاعدة البيانات عن username = DaveW، يتم إرجاع صفر صف. ومع ذلك، إذا بحثت عن

select * from users WHERE name = 'DaveW';

(الاسم وليس اسم المستخدم)، أحصل على صف واحد:

 19732 | DaveW    | 2016-11-15 12:43:02.708166 | 2016-11-15 12:43:02.708166 | DaveW |                    0 |                |               |      | t      | davew          | 2016-11-15 12:43:02.708166 | f     | 2017-06-01 18:09:45.018058 |           1 | f        |                |             |                   |              |                |               |     0 |          0 |            | f         |       |                    |        |                  |                         | f      |               |               |                          |                           | 
(صف واحد)

لاحظ كيف يحتوي على DaveW (نفس التهجئة) في حقل اسم المستخدم! هذا الحساب أقدم بثلاث سنوات من الحساب الآخر.

هل يمكنني التخلص منه باستخدام:

DELETE from users WHERE id = 19732;

دون أي آثار ضارة؟

شكرًا لك على كل مساعدتك!

غونار

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

بالطبع! :grinning:

هذا يجب أن يحذف 19732، لكن لا يمكنني ضمان عدم وجود أي آثار ضارة. وعلى أي حال، يُنصح بعمل نسخة احتياطية قبل المضي قدمًا.

3 إعجابات

قد ترغب أيضًا في تغيير اسم مستخدم أحد الحسابات المكررة.

إعجابَين (2)

صحيح.

بمجرد أن أفعل ذلك، هل يجب أن أتمكن من إعادة تشغيل الترقية من البداية؟ أي تشغيل إعادة البناء مرتين؟

شكرًا لك!
غونار

4 إعجابات

يجب أن يعمل ذلك. ما لم يكن هناك مستخدمون مكررون آخرون.

إعجابَين (2)

اتضح أن هناك مستخدمًا واحدًا على الأقل مكررًا.

PG::UniqueViolation: ERROR:  duplicate key value violates unique constraint "index_users_on_username_lower"
DETAIL:  Key (username_lower)=(robs) already exists.

هل توجد طريقة لمسح قاعدة البيانات بحثًا عن التكرارات؟ ليس فقط المستخدمين، بل أي جدول قد يتسبب في هذا الخطأ أثناء الترقية؟

أود العثور عليها وإصلاحها جميعًا قبل أن أحاول مرة أخرى.

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

إعجابَين (2)

قد تكون الطريقة الأقل تدخلاً هي إعادة فهرسة قاعدة البيانات قبل الترقية، مما يجب أن يخبرك بأي منها يحتاج إلى إصلاح.

إعجابَين (2)

لستُ خبيرًا في قواعد البيانات، لذا يبدو هذا الأمر مخيفًا. وإذا فهمتُ الأمر بشكل صحيح، فستنتهي بنتيجة مؤشرات مكررة، وستضطر إلى حذفها يدويًا؟

علاوة على ذلك، إليك الجزء الغريب. تمامًا كما اكتشفتَ في موقعي مع التكرار السابق، وجدتُ الآن مستخدمًا مكررًا باسم RobS في واجهة المستخدم الرسومية. ولكن، تمامًا كما حدث من قبل، بغض النظر عن أي منهما نقرتُ عليه، انتهى بي المطاف في صفحة الملف الشخصي لأحدهما فقط. أي:

  • قائمة المستخدمين المسماة RobS في واجهة المستخدم الرسومية. اعثر على اثنين. لاحظ أن كلاهما يمتلك إحصائيات مختلفة.
  • انقر على المستخدم رقم 1. شاهد الملف الشخصي والإحصائيات الخاصة بالمستخدم رقم 2.
  • انقر على المستخدم رقم 2. شاهد الملف الشخصي والإحصائيات الخاصة بالمستخدم رقم 2.

select * from users WHERE username_lower = 'robs';

تُرجع سطرًا واحدًا: ما يبدو أنه المستخدم رقم 2 (تتطابق التواريخ).

select * from users WHERE username = 'RobS';

تُرجع سطرًا واحدًا أيضًا: ما يبدو أنه المستخدم رقم 1 (مرة أخرى، تتطابق التواريخ). يمتلك هذا المستخدم معرفًا مختلفًا عن الآخر.

بناءً على المخرجات، يبدو أن كليهما كان يمتلك نفس username وusername_lower، ومع ذلك لم يُرجع كل بيان SELECT سوى سطر واحد. هل قاعدة البيانات الخاصة بي في حالة خطر جسيم؟

هل ستصلح إعادة الفهرسة هذه المشكلة؟

إعجابَين (2)

لقد حاولت إعادة البناء مرة أخرى، ووجدت تكرارًا آخر باسم مستخدم “drc”. في واجهة المستخدم الرسومية، وجدت هذين المستخدمين:

ديبورا سي
ديفيد سي

حاول النقر على أي من المستخدمين لعرض تفاصيلهما في “بطاقة” الملف الشخصي. ستلاحظ أنه بغض النظر عن أي منهما تنقر، ستظهر تفاصيل ديبورا سي.

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

كيف يمكنني إعادة الفهرسة؟ هل بهذه الطريقة؟

REINDEX SCHEMA CONCURRENTLY public;

هل سيخبرني ذلك عن المفاتيح المكررة؟

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

أتساءل عما سيردّ عليه ما يلي:

select id, username FROM users WHERE username_lower = 'robs' OR username = 'RobS':

هل الأمر تافهًا مثل وجود مسافات زائدة في أحد إدخالات اسم المستخدم، أو وجود حرف غير قابل للطباعة أو يونيكود بطريقة ما؟

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

أعتقد ذلك، ولا أعرف ما إذا كانت هناك طريقة أفضل للقيام بذلك. في مثيل الاختبار الخاص بي، يعمل فقط دون أي مخرجات. عند تحديث موقعي الإنتاجي، كان هناك تكرار واحد فقط للتعامل معه، لذا قد لا تكون تجربتي مثالًا جيدًا لوضعك. على أي حال، قم بنسخ احتياطي قبل عمليات قاعدة البيانات—عادةً ما أنشئ لقطة في DigitalOcean حتى يكون الاستعادة في حال حدوث مشكلة سريعًا وسهلًا.

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

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

إعجابَين (2)

شكرًا لك. عندما يفشل، كيف أجد وأتخلص من الفهرس الجديد غير المكتمل؟ هل الأمر بسيطًا مثل إضافة “_ccnew” إلى اسم الجدول الذي فشل؟

أي، عندما ينهار على “users” بسبب تكرار، هل أصلح التكرار أولاً، ثم:

DROP index ‘users_ccnew’;

ثم أكرر العملية؟ هل الأمر بهذه البساطة؟

شكرًا،
غونار

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

آه، نعم. لقد وجدتُ الآن حالتين لمستخدمين صالحين (ونشطين) لهما نفس اسم المستخدم ونفس username_lower:

  id   | username | (مخفي) | username_lower |
 42379 | DrC      | (مخفي) | drc            |
 47695 | DRC      | (مخفي) | drc            |

يبدو أنني بحاجة إلى تغيير اسم المستخدم و username_lower للمستخدم الثاني. كيف يمكنني فعل ذلك في psql؟

شكرًا لك!
غونار

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