TL;DR: ارتكبنا خطأً في ترقية النظام ونبحث عن مساعدة
نستخدم Home Assistant منصة Discourse لتشغيل مجتمعنا. نديرها باستخدام طريقة discourse_docker على مثيل EC2 من AWS.
بما أننا مشروع مفتوح المصدر، فقد سقط صيانة المنتدى بين الفجوات، وانتهى بنا المطاف بإصدار قديم، آخر تحديث له كان في بداية عام 2019.
ولجعل الأمر أسوأ، في ترقية سابقة، قمت بتثبيت Postgres على الإصدار 9.5 لأننا لم نكن نملك مساحة قرص كافية للترقية إلى Postgres 10. ولم نحل تلك المشكلة أبدًا.
كما قمنا مرة بتعديل قالب Cloudflare وقمنا بتسجيله في المستودع، مما منع فرع docker_discourse من التحديث إلى أحدث إصدار.
أمس، قررنا المضي قدمًا في الترقية…
عندما تم ترحيل قاعدة البيانات، واجهنا مشكلة أن الصيغة المستخدمة غير متوافقة مع الإصدار 9.5:
== 20200429095034 AddTopicThumbnailInformation: migrating =====================
-- execute("ALTER TABLE posts\nADD COLUMN IF NOT EXISTS image_upload_id bigint\n")
أدركنا بسرعة مشكلة تثبيت الإصدار 9.5. لذا قررنا الترحيل إلى Postgres 10. لكن ذلك لم ينجح وحصلنا على الخطأ التالي:
I, [2020-06-12T00:30:55.448351 #1] INFO -- : Upgrading PostgreSQL from version 9.5 to 10
WARNING: Upgrading PostgresSQL would require an addtional 89M of disk space
Please free up some space, or expand your disk, before continuing.
كان لدينا 47 جيجابايت متاحة، لذا كان ذلك غريبًا. ثم أدركنا أن discourse_docker كان قديمًا، فقمنا بتحديثه إلى أحدث إصدار. مفاجأة! لقد وصل Postgres 12 للتو.
بعد إعادة تشغيل rebuild هذه المرة، حصلنا على الخطأ التالي:
I, [2020-06-12T00:41:17.378129 #1] INFO -- : Upgrading PostgreSQL from version 9.5 to 12
WARNING: Upgrading PostgresSQL would require an addtional 92G of disk space
Please free up some space, or expand your disk, before continuing.
هذا يتطلب مساحة أكبر قليلاً، لكن لا بأس. لنقم بزيادة مساحة القرص إلى 300 جيجابايت ونحاول مرة أخرى.
في هذه المرة، فشل pg_upgrade أثناء الترحيل:
Restoring database schemas in the new cluster
template1
discourse
*failure* Consult the last few lines of "pg_upgrade_dump_16384.log" for the probable cause of the failure. Failure, exiting
عندما نظرنا إلى ملف pg_upgrade_dump_16384.log، رأينا الخطأ التالي:
pg_restore: creating VIEW "postgres_exporter.pg_stat_activity"
pg_restore: [archiver (db)] Error while PROCESSING TOC:
pg_restore: [archiver (db)] Error from TOC entry 721; 1259 678554 VIEW pg_stat_activity postgres
pg_restore: [archiver (db)] could not execute query: ERROR: column pg_stat_activity.waiting does not exist
LINE 27: "pg_stat_activity"."waiting",
^
Command was:
-- For binary upgrade, must preserve pg_type oid
SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('678556'::pg_catalog.oid);
-- For binary upgrade, must preserve pg_type array oid
SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('678555'::pg_catalog.oid);
-- For binary upgrade, must preserve pg_class oids
SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('678554'::pg_catalog.oid);
CREATE VIEW "postgres_exporter"."pg_stat_activity" AS
SELECT "pg_stat_activity"."datid",
"pg_stat_activity"."datname",
"pg_stat_activity"."pid",
"pg_stat_activity"."usesysid",
"pg_stat_activity"."usename",
"pg_stat_activity"."application_name",
"pg_stat_activity"."client_addr",
"pg_stat_activity"."client_hostname",
"pg_stat_activity"."client_port",
"pg_stat_activity"."backend_start",
"pg_stat_activity"."xact_start",
"pg_stat_activity"."query_start",
"pg_stat_activity"."state_change",
"pg_stat_activity"."waiting",
"pg_stat_activity"."state",
"pg_stat_activity"."backend_xid",
"pg_stat_activity"."backend_xmin",
"pg_stat_activity"."query"
FROM "pg_stat_activity";
يا إلهي.
لذا قررنا هنا اتخاذ عدة خطوات للخلف. هل يمكننا فقط إعادة تشغيل المنتدى وجعله في وضع القراءة فقط بينما نحلل مشكلة النسخ الاحتياطي؟ تمكنا من القيام بذلك عن طريق إصلاح بعض مشكلات الأذونات لكل من postgres وredis، وعاد المنتدى للعمل على الإصدار القديم. لا يعمل كل شيء، فمثلاً عند الانتقال إلى admin → user → groups نحصل على هذا الخطأ:
NoMethodError (undefined method `automatic_membership_retroactive' for #<Group:0x00007fcaca3045e8>)
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/attribute_methods.rb:431:in `method_missing'
لكن الباقي يبدو أنه يعمل.
في هذه النقطة، قررنا أنه نظرًا لأننا اضطررنا إلى تغيير ملكية الملفات (chown) للعودة إلى مثيل يعمل، يجب علينا ببساطة بدء مثيل جديد واستيراد نسخة الاحتياطية لدينا.
لذا قمنا ببدء مثيل EC2 جديد، وتنفيذ تعليمات البدء السريع لـ discourse_docker، وبدأنا استيرادنا. ثم واجهنا مشكلة غريبة: لم يتمكن من إنشاء فهرس لأن البيانات لا تتطابق مع متطلبات التفرد للفهرس:
ERROR: could not create unique index "index_incoming_domains_on_name_and_https_and_port"
DETAIL: Key (name, https, port)=(homeassistant.home, f, 8123) is duplicated.
EXCEPTION: psql failed: DETAIL: Key (name, https, port)=(homeassistant.home, f, 8123) is duplicated.
/var/www/discourse/lib/backup_restore/database_restorer.rb:95:in `restore_dump'
ولكن عندما دخلنا إلى وحدة تحكم rails في مثيلنا الجاري، لم تكن هناك تكرار:
[7] pry(main)> IncomingDomain.where(name: "homeassistant.home")
=> [#<IncomingDomain:0x000055e5cabc3760 id: 8648, name: "homeassistant.home", https: false, port: 8123>]
إذن هذا هو وضعنا الحالي. ونحن في حيرة من أمرنا.
- لدينا مثيل يعمل بقاعدة بيانات سيئة مقارنة بكود Ruby غير القادر على الترقية إلى إصدار أحدث من Postgres
- لدينا نسخة احتياطية لا يمكن استيرادها في مثيل جديد
استكشفنا إمكانية الانتقال إلى Discourse مستضاف مدفوع، لكن نظرًا لأن لدينا 3 ملايين مشاهدة صفحة ومليون منشور، فإن التسعير المؤسسي يمثل التزامًا كبيرًا جدًا بالنسبة لنا.
لذا نحتاج إلى إيجاد مخرج، ونفضل أن نستطيع استيراد نسخة الاحتياطية، لكن ترحيل مثيلنا القديم سيعمل أيضًا.
هل لدى أي شخص أي أفكار؟ لا مانع لدينا من دفع مبلغ لشخص ما لمساعدتنا أيضًا.