فشل استعادة النسخة الاحتياطية

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

الخادم القديم يعمل بالإصدار: 3.4.0.beta4-dev

الخادم الجديد: أحدث إصدار

حجم النسخة الاحتياطية هو بالفعل 673.2 ميجابايت كملف .gz، باستثناء الملفات المرفوعة

للأسف، تتعطل عملية الاستعادة باستمرار. يحتوي ملف السجل على هذه الرسالة:

[2026-06-16 07:54:52] ERROR:  could not create unique index "index_incoming_referers_on_path_and_incoming_domain_id"
[2026-06-16 07:54:52] DETAIL:  Key (path, incoming_domain_id)=(//, 5) is duplicated.
[2026-06-16 07:54:52] EXCEPTION: psql failed: DETAIL:  Key (path, incoming_domain_id)=(//, 5) is duplicated.

[2026-06-16 07:54:52] /var/www/discourse/lib/backup_restore/database_restorer.rb:93:in 'BackupRestore::DatabaseRestorer#restore_dump'
/var/www/discourse/lib/backup_restore/database_restorer.rb:26:in 'BackupRestore::DatabaseRestorer#restore'
/var/www/discourse/lib/backup_restore/restorer.rb:61:in 'BackupRestore::Restorer#run'
/var/www/discourse/script/spawn_backup_restore.rb:20:in 'Object#restore'
/var/www/discourse/script/spawn_backup_restore.rb:33:in 'block in '
/var/www/discourse/script/spawn_backup_restore.rb:4:in 'Kernel#fork'
/var/www/discourse/script/spawn_backup_restore.rb:4:in ''
[2026-06-16 07:54:52] Trying to rollback...

ما الذي يمكنني فعله لحل هذه المشكلة دون فقدان آخر 10 سنوات من البيانات؟

شكرًا مقدّمًا على أي مساعدة!

مرحباً وواو، أهلاً بعودتك بعد 9 سنوات!

من الرائع جداً رؤية منتدى يعمل منذ فترة طويلة.

أعتقد أن هذه هي مشكلة الفهرس نفسها التي نوقشت هنا: Can't restore due to corrupt indexes (with some clues on how to deal with corrupt indexes)

الأمر يتعلق بما يلي:

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

قاعدة البيانات الخاصة بك تحتوي على صفين مع path='//' و incoming_domain_id=5. عندما تحاول إعادة بناء هذا الفهرس الفريد أثناء الاستعادة، تجد التكرار وتوقف عملية الاستعادة بأكملها.

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

لقد وجدت هذا الموضوع الذي يحتوي على تعليمات قد يساعدك

شكرًا جزيلاً على ردك السريع؛ سأحاول ذلك!

(تم حذف المنشور من قبل الكاتب)

عذرًا على الإزعاج، لكن يبدو أنني أقوم بشيء خاطئ — بعد تشغيل الأمر “discourse=# select * from incoming_referers where path LIKE ‘%/search/’ ORDER BY incoming_domain_id;”، أحصل على خطأ في بناء الجملة.

هل قمت بكتابة “discourse=#”؟ إذا كان الأمر كذلك، حاول مرة أخرى بدون ذلك

ثم أحصل على رسالة الخطأ “bash: syntax error near unexpected token `from’”

للمرجع، أنا حاليًا في: root@community-app:/var/www/discourse#

آه، أنت لم تدخل قاعدة البيانات بعد.

قم أولاً بتشغيل الأمر psql -U discourse discourse (أعتقد)

وعندها يجب أن يتغير المؤشر إلى discourse=#

حسنًا، قمت الآن بتثبيت “apt install postgresql-client-common”. ومع ذلك، لا زلت أحصل على الخطأ “خطأ: يجب عليك تثبيت حزمة postgresql-client- واحدة على الأقل.”

حسناً، هذا لا أعرفه.

ربما حاولت مباشرة عبر وحدة تحكم Rails ثم: rails c

مع

ActiveRecord::Base.connection.execute(<<~SQL)
  SELECT id, path, incoming_domain_id 
  FROM incoming_referers 
  WHERE path = '//' 
  AND incoming_domain_id = 5
SQL

قد يعطيك ذلك نفس النتيجة دون المرور عبر قاعدة البيانات.

هل يعمل ذلك؟

أنا آسف حقًا، حقًا جدًا على تصرفي بهذه الطريقة الغبية.

لقد قمت الآن بتثبيت Rails، ويبدو أن الأمر قد نجح. كما قمت بتشغيله باستخدام الأمر "rails c". يبدو أن هذا أيضًا يعمل، ولكن عند إدخال الأمر، يظهر بالشكل التالي:

"root@community:/var/discourse# ActiveRecord::Base.connection.execute(<<~SQL)
-bash: syntax error near unexpected token \'<<'
root@community:/var/discourse# SELECT id, path, incoming_domain_id
SELECT: command not found
root@community:/var/discourse# FROM incoming_referers
FROM: command not found
root@community:/var/discourse# WHERE path = ‘//’
WHERE: command not found
root@community:/var/discourse# AND incoming_domain_id = 5
AND: command not found
root@community:/var/discourse# SQL"

لا تقلق، ربما تعليماتي ليست واضحة بما يكفي :slight_smile:

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

على أي حال، بمجرد دخولك إلى Rails، يجب أن يتغير الموجه (prompt)، لذا يبدو من مخرجاتك أنك لم تدخل إلى وحدة تحكم Rails بعد.

أعتقد حتى أنك لم تدخل إلى الحاوية الفعلية. هل قمت بتشغيل ./launcher enter app؟

حسنًا، نعم، كانت هذه هي المشكلة. استعلام التشغيل نجح الآن، وقد حصلت على هذا الرد:

#<PG::Result:0x00007fbde9732ef0 status=PGRES_TUPLES_OK ntuples=1 nfields=3 cmd_tuples=1>

إذن، ntuples=1 تعني أنه تم العثور على صف واحد فقط، بينما يشير سجل الخطأ إلى وجود تكرار… :woman_shrugging:

آسف، لا أعرف ما يمكنني تجربته بعد ذلك. أنصحك بتصفح المنتدى، يبدو أن هناك العديد من الحالات المشابهة (انظر أدناه هذا الموضوع في القسم ذي الصلة)، ربما تجد هناك الدليل التالي.

(أو انتظر حتى يمر شخص أكثر خبرة بسهولة ;))

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

على الخادم القديم، افتح وحدة تحكم Rails:

./launcher enter app
rails c

ثم الصق الأسطر التالية، واحدة تلو الأخرى:

db = ActiveRecord::Base.connection.current_database
DB.exec("DELETE FROM incoming_referers a USING incoming_referers b WHERE a.id > b.id AND a.path = b.path AND a.incoming_domain_id = b.incoming_domain_id")
DB.exec("REINDEX DATABASE #{ActiveRecord::Base.connection.quote_table_name(db)}")

هذا الإجراء يزيل التكرار ويعيد بناء جميع الفهارس (في حال تأثرت جداول أخرى أيضًا).

إذا اكتملت عملية REINDEX دون ظهور خطأ، اكتب exit، ثم أنشئ نسخة احتياطية جديدة على الخادم القديم، واستعد الملف الجديد. وإذا ظهر خطأ يتعلق بجدول آخر، فقط انسخه وألصقه هنا.

شكرًا جزيلاً. للأسف، أحصل على رسالة خطأ في السطر الأخير:

«PG::InsufficientPrivilege: ERROR: يجب أن يكون المالك لقاعدة بيانات discourse»

من المفترض أن يكون الخادم بالفعل «خادمًا قياسيًا». تم تنفيذ التثبيت من قبل فريق «Discourse» في ذلك الوقت مقابل رسوم لمرة واحدة.

آه، صحيح. دعنا نجرب هذا.

أغلق وحدة تحكم Rails (اكتب exit)، وفيما لا تزال داخل الحاوية (./launcher enter app)، قم بتشغيل:

su postgres -c "reindexdb discourse"

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

شكرًا جزيلاً لك! كل شيء سار بشكل رائع، وبدون مساعدتي ما كنتُ لأملك أي فرصة، ولضطررتُ حتمًا إلى إعادة إنشاء المنتدى من الصفر بعد ألمٍ شديد! شكرًا جزيلاً!

كما أشكر @chapoi على الدعم الرائع!