المساعدة في الاستعادة - تعطل النظام عند منتصف الليل

Okay this was bound to happen, things were just too good for too long. Years of running on cruise control, the system would automatically update itself and I would update Discourse every few weeks. At midnight last night, Amazon showed the system was unresponsive, discourse was down and the CPU was pegged at 100% until it ran out of AWS CPU resources. Couldn’t login to the system, the one time after several reboots I was able to login momentarily, I saw this in htoptaking up a lot of CPU

snap lxd activate

If anyone has seen this can can throw some light as to why this may happened by itself, it would be much appreciated for future reference.

Coming the pressing issue at hand, I proceeded to rebuild a new server on AWS using Ubuntu 20LTS, Discourse setup was exceedingly easy. I had a copy of the app.yml file which I used to recreate the discourse forum. The old server was using S3 for the backups AND for the content (images etc).

After creating the server, I downloaded the latest discourse backup file from S3, manually uploaded it to the discourse server and hit the Restore buttons. After a few minutes I get this error.

[2022-06-09 09:01:56] ALTER TABLE
[2022-06-09 09:01:56] ALTER TABLE
[2022-06-09 09:01:56] Migrating the database...
[2022-06-09 09:02:11] == 20220308201942 CreateUploadReferences: migrating ===========================
-- create_table(:upload_references, {})
   -> 0.0486s
-- add_index(:upload_references, [:upload_id, :target_type, :target_id], {:unique=>true, :name=>"index_upload_references_on_upload_and_target"})
   -> 0.0030s
== 20220308201942 CreateUploadReferences: migrated (0.0580s) ==================

== 20220309132719 CopyPostUploadsToUploadReferences: migrating ================
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT post_uploads.upload_id, 'Post', post_uploads.post_id, uploads.created_at, uploads.updated_at\nFROM post_uploads\nJOIN uploads ON uploads.id = post_uploads.upload_id\nON CONFLICT DO NOTHING\n")
   -> 0.0595s
== 20220309132719 CopyPostUploadsToUploadReferences: migrated (0.0602s) =======

== 20220309132720 CopyPostUploadsToUploadReferencesForSync: migrating =========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT upload_id, 'Post', post_id, NOW(), NOW()\nFROM post_uploads\nON CONFLICT DO NOTHING\n")
   -> 0.0076s
== 20220309132720 CopyPostUploadsToUploadReferencesForSync: migrated (0.0080s) 

== 20220330160747 CopySiteSettingsUploadsToUploadReferences: migrating ========
-- execute("WITH site_settings_uploads AS (\n  SELECT id, unnest(string_to_array(value, '|'))::integer upload_id\n  FROM site_settings\n  WHERE data_type = 17\n  UNION\n  SELECT id, value::integer\n  FROM site_settings\n  WHERE data_type = 18 AND value != ''\n)\nINSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT site_settings_uploads.upload_id, 'SiteSetting', site_settings_uploads.id, uploads.created_at, uploads.updated_at\nFROM site_settings_uploads\nJOIN uploads ON uploads.id = site_settings_uploads.upload_id\nON CONFLICT DO NOTHING\n")
   -> 0.0034s
== 20220330160747 CopySiteSettingsUploadsToUploadReferences: migrated (0.0038s) 

== 20220330160751 CopyBadgesUploadsToUploadReferences: migrating ==============
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT badges.image_upload_id, 'Badge', badges.id, uploads.created_at, uploads.updated_at\nFROM badges\nJOIN uploads ON uploads.id = badges.image_upload_id\nWHERE badges.image_upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0006s
== 20220330160751 CopyBadgesUploadsToUploadReferences: migrated (0.0010s) =====

== 20220330160754 CopyGroupsUploadsToUploadReferences: migrating ==============
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT groups.flair_upload_id, 'Group', groups.id, uploads.created_at, uploads.updated_at\nFROM groups\nJOIN uploads ON uploads.id = groups.flair_upload_id\nWHERE groups.flair_upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0050s
== 20220330160754 CopyGroupsUploadsToUploadReferences: migrated (0.0055s) =====

== 20220330160757 CopyUserExportsUploadsToUploadReferences: migrating =========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT user_exports.upload_id, 'UserExport', user_exports.id, uploads.created_at, uploads.updated_at\nFROM user_exports\nJOIN uploads ON uploads.id = user_exports.upload_id\nON CONFLICT DO NOTHING\n")
   -> 0.0013s
== 20220330160757 CopyUserExportsUploadsToUploadReferences: migrated (0.0041s) 

== 20220330164740 CopyThemeFieldsUploadsToUploadReferences: migrating =========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT theme_fields.upload_id, 'ThemeField', theme_fields.id, uploads.created_at, uploads.updated_at\nFROM theme_fields\nJOIN uploads ON uploads.id = theme_fields.upload_id\nWHERE type_id = 2\nON CONFLICT DO NOTHING\n")
   -> 0.0006s
== 20220330164740 CopyThemeFieldsUploadsToUploadReferences: migrated (0.0010s) 

== 20220404195635 CopyCategoriesUploadsToUploadReferences: migrating ==========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT categories.uploaded_logo_id, 'Category', categories.id, uploads.created_at, uploads.updated_at\nFROM categories\nJOIN uploads ON uploads.id = categories.uploaded_logo_id\nWHERE categories.uploaded_logo_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0095s
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT categories.uploaded_background_id, 'Category', categories.id, uploads.created_at, uploads.updated_at\nFROM categories\nJOIN uploads ON uploads.id = categories.uploaded_background_id\nWHERE categories.uploaded_background_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0004s
== 20220404195635 CopyCategoriesUploadsToUploadReferences: migrated (0.0103s) =

== 20220404201949 CopyCustomEmojisUploadsToUploadReferences: migrating ========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT custom_emojis.upload_id, 'CustomEmoji', custom_emojis.id, uploads.created_at, uploads.updated_at\nFROM custom_emojis\nJOIN uploads ON uploads.id = custom_emojis.upload_id\nWHERE custom_emojis.upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0032s
== 20220404201949 CopyCustomEmojisUploadsToUploadReferences: migrated (0.0036s) 

== 20220404203356 CopyUserProfilesUploadsToUploadReferences: migrating ========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT user_profiles.profile_background_upload_id, 'UserProfile', user_profiles.user_id, uploads.created_at, uploads.updated_at\nFROM user_profiles\nJOIN uploads ON uploads.id = user_profiles.profile_background_upload_id\nWHERE user_profiles.profile_background_upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0017s
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT user_profiles.card_background_upload_id, 'UserProfile', user_profiles.user_id, uploads.created_at, uploads.updated_at\nFROM user_profiles\nJOIN uploads ON uploads.id = user_profiles.card_background_upload_id\nWHERE user_profiles.card_background_upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0011s
== 20220404203356 CopyUserProfilesUploadsToUploadReferences: migrated (0.0033s) 

== 20220404204439 CopyUserAvatarsUploadsToUploadReferences: migrating =========
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT user_avatars.custom_upload_id, 'UserAvatar', user_avatars.id, uploads.created_at, uploads.updated_at\nFROM user_avatars\nJOIN uploads ON uploads.id = user_avatars.custom_upload_id\nWHERE user_avatars.custom_upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0200s
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT user_avatars.gravatar_upload_id, 'UserAvatar', user_avatars.id, uploads.created_at, uploads.updated_at\nFROM user_avatars\nJOIN uploads ON uploads.id = user_avatars.gravatar_upload_id\nWHERE user_avatars.gravatar_upload_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0069s
== 20220404204439 CopyUserAvatarsUploadsToUploadReferences: migrated (0.0276s) 

== 20220404212716 CopyThemeSettingsUploadsToUploadReferences: migrating =======
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT theme_settings.value::int, 'ThemeSetting', theme_settings.id, uploads.created_at, uploads.updated_at\nFROM theme_settings\nJOIN uploads ON uploads.id = theme_settings.value::int\nWHERE data_type = 6 AND theme_settings.value IS NOT NULL AND theme_settings.value != ''\nON CONFLICT DO NOTHING\n")
   -> 0.0025s
== 20220404212716 CopyThemeSettingsUploadsToUploadReferences: migrated (0.0030s) 

== 20220526203356 CopyUserUploadsToUploadReferences: migrating ================
-- execute("INSERT INTO upload_references(upload_id, target_type, target_id, created_at, updated_at)\nSELECT users.uploaded_avatar_id, 'User', users.id, uploads.created_at, uploads.updated_at\nFROM users\nJOIN uploads ON uploads.id = users.uploaded_avatar_id\nWHERE users.uploaded_avatar_id IS NOT NULL\nON CONFLICT DO NOTHING\n")
   -> 0.0227s
== 20220526203356 CopyUserUploadsToUploadReferences: migrated (0.0234s) =======


[2022-06-09 09:02:11] Reconnecting to the database...
[2022-06-09 09:02:12] Reloading site settings...
[2022-06-09 09:02:12] Disabling outgoing emails for non-staff users...
[2022-06-09 09:02:14] Disabling readonly mode...
[2022-06-09 09:02:14] Clearing category cache...
[2022-06-09 09:02:14] Reloading translations...
[2022-06-09 09:02:14] Remapping uploads...
[2022-06-09 09:02:14] Restoring uploads, this may take a while...
[2022-06-09 09:03:05] EXCEPTION: 509 of 1823 uploads are not migrated to S3. S3 migration failed for db 'default'.
[2022-06-09 09:03:05] /var/www/discourse/lib/file_store/to_s3_migration.rb:132:in `raise_or_log'
/var/www/discourse/lib/file_store/to_s3_migration.rb:79:in `migration_successful?'
/var/www/discourse/lib/file_store/to_s3_migration.rb:373:in `migrate_to_s3'
/var/www/discourse/lib/file_store/to_s3_migration.rb:66:in `migrate'
/var/www/discourse/lib/file_store/s3_store.rb:328:in `copy_from'
/var/www/discourse/lib/backup_restore/uploads_restorer.rb:62:in `restore_uploads'
/var/www/discourse/lib/backup_restore/uploads_restorer.rb:44:in `restore'
/var/www/discourse/lib/backup_restore/restorer.rb:61:in `run'
/var/www/discourse/script/spawn_backup_restore.rb:23:in `restore'
/var/www/discourse/script/spawn_backup_restore.rb:36:in `block in <main>'
/var/www/discourse/script/spawn_backup_restore.rb:4:in `fork'
/var/www/discourse/script/spawn_backup_restore.rb:4:in `<main>'

Can anyone advise on what’s the problem and how I can restore the server from the Amazon S3 server backups?

مرحباً،
بعد إعادة إنشاء الخادم الجديد من app.yml، هل تمكنت من الوصول إلى النسخ الاحتياطية في قسم https://your.domain/admin/backups؟

لا، بعد إعادة الإنشاء من app.yml، أعطاني إعدادًا جديدًا ونظيفًا بدون أي شيء. قمت بتنزيل آخر نسخة احتياطية من S3 وقمت بتحميلها يدويًا إلى discourse محليًا وقمت بالضغط على استعادة.

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

:thinking: إذن إعدادات S3 ليست في app.yml (كما هو موضح هنا Configure an S3 compatible object storage provider for uploads)؟ ولكن تم تكوينها كما في Set up file and image uploads to S3

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

لا، لا أرى هذا في ملف app.yml الخاص بي.

تم تعريف جميع إعدادات S3 في صفحات المسؤول → الإعدادات وكانت تعمل بشكل جيد لمدة عام حتى احتجت إلى استعادتها عندما تعطل الخادم الليلة الماضية.

صحيح، هذا ما استخدمته لإعداد النسخ الاحتياطي والتحميلات لـ S3.

أعتقد أنني سأحاول تعديل ملف app.yml بالإعدادات الخاصة بك ومن هناك أعتقد (آمل؟) أن ترى النسخ الاحتياطية الخاصة بك في قسم المسؤول واستعادتها من هناك، دون الاستيراد اليدوي والتحميلات، والتي لا ينبغي لك استعادتها، ولكن يبدو أنها مدرجة في النسخ الاحتياطية. لا أعرف لماذا يفشل الأمر على الرغم من ذلك…

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

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

إعجابَين (2)

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

لذا أتساءل ما هي خياراتي الآن؟ هل هناك طريقة للاستعادة من النسخ الاحتياطي لـ S3 وتجاهل الملفات المحلية؟ لقد وجدت طريقة لجعله يتجاهل التحميل إلى S3 ولكن بعد ذلك فإن معظم المشاركات لديها روابط/صور معطلة (90٪+ ربما في S3 لأنني قمت بإعداد التحميل إلى S3 منذ سنوات عديدة).

إليك تحديث لمن قد يواجهون نفس المشكلة (بشكل أساسي، لا يمكنني الاستعادة من نسخة احتياطية وتعطل الخادم بسبب ترقية نظام خاطئة).

حسب فهمي، فإن السبب الجذري للمشكلة هو وجود عمليات تحميل محلية وعمليات تحميل S3، لذلك عندما تحاول أداة الاستعادة الاستعادة، فإنها تتعطل لأنها لا تعرف كيفية التعامل مع عمليات الاستعادة المحلية و S3 في نفس الوقت (ربما حان الوقت لـ Discourse لإعادة النظر في النسخ الاحتياطي/الاستعادة).

بفضل @RGJ لهذه النصيحة، اقترح إجبار Discourse على تجاهل تحميل S3 أثناء الاستعادة:

  1. أضف سطرًا إلى ملف app.yml الخاص بك DISCOURSE_ENABLE_S3_UPLOADS=false
  2. أعد بناء Discourse ./launcher rebuild app
  3. حاول الاستعادة (إما من صفحة النسخ الاحتياطي في واجهة المستخدم الرسومية أو باستخدام واجهة سطر الأوامر)
  4. ثم بعد الاستعادة، قم بإزالة هذا السطر من app.yml وأعد البناء مرة أخرى

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

الحل الأخير:
تمكنت من إنقاذ الخادم القديم واستخراج الدليل /var/discourse (tar/gz) ونسخه إلى الخادم الجديد وقمت بتشغيل ./launcher rebuild app. هذا استعاد تشغيل المنتدى بالكامل، ومع ذلك، لا تزال المشكلة الأساسية قائمة - النسخ الاحتياطي لن يعمل لأنها تحتوي على مزيج من التحميلات المحلية و S3.

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

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

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

 rake uploads:migrate_to_s3

إذا كنت ترغب في التوقف عن استخدام S3، فيمكنك الدخول إلى وحدة تحكم rails وتعيين:

  SiteSetting.include_s3_uploads_in_backups=true

ثم قم بأخذ نسخة احتياطية، وتأكد من أنك لا قمت بتكوين S3 في ملف app.yml الخاص بك وقم باستعادة النسخة الاحتياطية. أعتقد أن هذا سيؤدي إلى استعادة النسخ الاحتياطية إلى المحلية.

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

إعجابَين (2)

حسنًا، أعتقد أنني اختلطت قليلاً هنا.

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

لذا، إذا فهمت بشكل صحيح، يجب أن أتبع هذه التعليمات:

إذا كنت ترغب في التوقف عن استخدام S3، فيمكنك الدخول إلى وحدة تحكم Rails وتعيين
  SiteSetting.include_s3_uploads_in_backups=true
ثم قم بعمل نسخة احتياطية، وتأكد من عدم تكوين S3 في ملف app.yml الخاص بك واستعادة النسخة الاحتياطية. أعتقد أن هذا سيؤدي إلى استعادة النسخ الاحتياطية محليًا.

ثم

  1. قم بتعطيل خيار تمكين التحميل إلى S3 في المسؤول → الإعدادات → الملفات
  2. قم بتمكين خيار النسخ الاحتياطي إلى S3 في صفحة المسؤول → الإعدادات → النسخ الاحتياطية

هل هذا صحيح؟

هذا هو الجزء الذي أربكني، لماذا أرغب في وضع تكوين S3 في ملف app.yml؟

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

أعتقد أن أفضل ممارسة هي تكوين S3 فقط عبر متغيرات البيئة في ملف app.yml. ربما يكون من المنطقي جعلها إعدادات مخفية، إن لم يكن لمئات الأشخاص الذين سيتفاجأون باختفائها.

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

لأنك ستواجه صعوبة في الاستعادة بخلاف ذلك.

إعجابَين (2)

كيف يمكن للمرء استعادة نسخة احتياطية من S3 باستخدام سطر الأوامر؟ وفقًا للتعليمات هنا: Restore a backup from the command line
يقول أنه يمكنك إسقاط ملف النسخ الاحتياطي في مجلد /var/discourse/shared/standalone/backups/default ثم بدء استعادة من سطر الأوامر. هذا ما فعلته باقتراحك سابقًا (والذي أدى في النهاية إلى روابط معطلة للأسف)، ولكنه يعمل.

كيف يمكن للمرء الاستعادة مباشرة من S3 باستخدام سطر الأوامر؟

cd /var/discourse
./launcher enter app
discourse restore

سيقوم بطباعة النسخ الاحتياطية المتاحة التي يمكنك بعد ذلك نسخ/لصق النسخة التي تريد إجراء الاستعادة منها.

إعجابَين (2)

شكرًا، لذا سيقرأ النسخ الاحتياطية لـ S3 ويسردها كخيار.

جاي، متابعةً لاقتراح قدمته بشأن نقل الأصول محليًا:

أعتقد أنه يمكنك تعيين إعداد مخفي include_s3_uploads_in_backups إلى صحيح ثم إجراء نسخة احتياطية واستعادتها عند إيقاف تشغيل S3 للتوقف عن استخدام S3.

وجود نسخ احتياطية لـ S3 مع تكوينها في app.yml يعني أنه يمكنك إجراء استعادة من سطر الأوامر باستخدام ملف app.yml فقط (بعد استنساخ discourse وتثبيت docker).

للخطوة الأولى، هل أحتاج إلى عمل نسخة احتياطية من S3 buckets أم أن هذه عملية آمنة للـ bucket؟

حسنًا، على الأقل اكتشفت سبب تعطل خادمي الليلة الماضية (ومرة أخرى اليوم بعد إعادة بناء كاملة :frowning: ، انظر هذا الموضوع للتفاصيل: Ubuntu 20.04 kernel update with docker causing a crash on EC2 and Lightsail

إعجابَين (2)

لذلك، لتشغيله من نسخة احتياطية، كان عليّ

  1. تعطيل الإعدادات → الملفاتتمكين تحميلات S3
  2. الإعدادات → النسخ الاحتياطيةموقع النسخ الاحتياطيS3
  3. تمكين الإعدادات → النسخ الاحتياطيةالنسخ الاحتياطي مع التحميلات

بعد ذلك، أخذت نسخة احتياطية وتمكنت من استعادتها بنجاح. ومع ذلك، تعطل شيء واحد، جميع المرفقات (الملفات) لم تعد تحتوي على روابط غير صالحة. الصور كلها جيدة، ولكن روابط المرفقات مثل https://domain.com/uploads/short-url/phu1HOLvkE8LWpkKYfnMPSWsvHh.zip تعطيني الآن خطأ

عفوًا! هذه الصفحة غير موجودة أو خاصة.

هل هناك طريقة لإصلاح روابط عناوين URL القصيرة هذه؟

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

شكرًا. هل يوجد دليل في مكان ما حول كيفية إصدار الأمر لخبز مواضيع محددة؟