شوبيفاي تستعين بوكلاء الذكاء الاصطناعي لخفض استهلاك ذاكرة خوادم ريلز

Ractors, Rails, and Robots: Automating the Path to Ractor-safety - Andrew Novoselac — Ruby on Rails

Ruby on Rails

يخفض تشغيل ريلز عبر تقنية راكتور استهلاك الذاكرة بسبعة أضعاف، لكن تجميد الكائنات والاعتماد على الراكتور الرئيسي لعمليات قواعد البيانات يفرضان زيادة مؤقتة في زمن الاستجابة بنسبة 25%.

AI-assisted summary of Ractors, Rails, and Robots: Automating the Path to Ractor-safety - Andrew Novoselac — original source. Check the original for full context.

Source published:

Key ideas

  • تتيح وحدات Ractors تنفيذ كود Ruby بالتوازي الحقيقي داخل عملية واحدة بفضل امتلاك كل راكتور لقفل GVL مستقل مع مشاركة الذاكرة، مما يجمع مزايا العمليات والخيوط. (1:12)
  • أظهرت تجارب Shopify المقارنة بين خادم Ractor التجريبي Keno وخادم Puma استهلاك Puma لنحو 7 أضعاف الذاكرة، مقابل زيادة بنسبة 25% في زمن الاستجابة على Keno نتيجة حصر مهام الإدخال والإخراج في راكتور رئيسي. (4:06)
  • استخدم فريق Shopify حلقة وكيل ذكاء اصطناعي بتكلفة قرابة 2,000 دولار من أرصدة Claude 3 Opus لاكتشاف وتغطية 67% من قاعدة كود Rails وتأمين 169 مساراً برمجياً في أسبوعين فقط. (15:32)
  • ساهم الفريق بأكثر من 100 طلب سحب إلى Rails، مستفيداً من أداة 'فحص العزل' (isolation check) التي تسجل انتهاكات الذاكرة دون إيقاف تشغيل الخادم لمعالجة الثوابت وحالات الفئات. (20:33)

Detailed notes

## Background نُشر هذا العرض التقديمي عبر قناة Ruby on Rails على منصة يوتيوب في الأول من أكتوبر 2026، من مؤتمر Rails World 2026. يقدّم المحاضرة أندرو نوفوسيلاك، مطور البنية التحتية لـ Ruby on Rails في شركة شوبيفاي، متناولاً الجهود التقنية المبذولة لجعل إطار عمل Rails آمناً ومتوافقاً مع نماذج التزامن Ractors لتشغيل خوادم الويب بكفاءة واستهلاك ذاكرة أقل.

## TL;DR يستعرض أندرو نوفوسيلاك الفروق الجوهرية في التزامن بين العمليات والخيوط وRactors في روبي، مبيناً كيف يتيح خادم الويب القائم على Ractor توازياً حقيقياً مع توفير هائل في استهلاك الذاكرة. ويوضح العوائق الهندسية الشديدة التي تحول دون جعل إطار عمل ضخم مثل Rails آمناً مع Ractor بسبب قيود التجميد العميق للأشياء وتتابع الأخطاء غير القابلة للحل اليدوي المتوازي. لمواجهة هذا التعقيد، استعان الفريق بحلقة وكيل ذكاء اصطناعي (AI agent loop) لاختبار وتوليد مسارات برمجية غطت قرابة 67% من كود Rails ورسمت خارطة عمل استكشافية شاملة. وأخيراً، يعرض التعديلات التي تم دمجها بالفعل في نواة الإطار، ونمط فحص العزل الليلي، والتحديات العالقة في الوصول لقواعد البيانات، موجهاً دعوة مفتوحة لمجتمع روبي للمساهمة في تحقيق هذا الهدف.

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

## Bulletin - [01:12](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=72s) تتيح وحدات Ractors تنفيذ كود Ruby بالتوازي الحقيقي داخل عملية واحدة بفضل امتلاك كل راكتور لقفل GVL مستقل مع مشاركة الذاكرة، مما يجمع مزايا العمليات والخيوط. - [04:06](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=246s) أظهرت تجارب Shopify المقارنة بين خادم Ractor التجريبي Keno وخادم Puma استهلاك Puma لنحو 7 أضعاف الذاكرة، مقابل زيادة بنسبة 25% في زمن الاستجابة على Keno نتيجة حصر مهام الإدخال والإخراج في راكتور رئيسي. - [15:32](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=932s) استخدم فريق Shopify حلقة وكيل ذكاء اصطناعي بتكلفة قرابة 2,000 دولار من أرصدة Claude 3 Opus لاكتشاف وتغطية 67% من قاعدة كود Rails وتأمين 169 مساراً برمجياً في أسبوعين فقط. - [20:33](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=1233s) ساهم الفريق بأكثر من 100 طلب سحب إلى Rails، مستفيداً من أداة 'فحص العزل' (isolation check) التي تسجل انتهاكات الذاكرة دون إيقاف تشغيل الخادم لمعالجة الثوابت وحالات الفئات.

## Key takeaways - [01:12](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=72s) تتغلب Ractors على قيود العمليات (العزل التام واستهلاك الذاكرة) والخيوط (غياب التوازي الفعلي بسبب GVL الموحد) بامتلاك كل راكتور لقفل GVL مستقل مع مشاركة الذاكرة. - [04:06](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=246s) الدافع الاقتصادي والهندسي وراء خوادم الويب المعتمدة على Ractor هو خفض التكلفة الباهظة للذاكرة المادية وزيادة التزامن دون التضحية بالموارد. - [07:27](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=447s) يفرض أمان Ractor في لغة Ruby شرط التجميد العميق الصارم لكافة الكائنات ومتغيرات الحالة التابعة لها عبر Ractor.make_shareable. - [09:22](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=562s) تعطلت المحاولات الأولية لتشغيل Rails داخل Ractor بسبب إجراءات التهيئات المرتبطة بـ self وخرائط Concurrent::Map غير القابلة للتجميد في مكتبات مثل Solid Cache. - [12:40](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=760s) الأسلوب البشري اليدوي كان بطيئاً ومعقداً بسبب غياب القدرة على التوازي وظهور خطأ واحد تلو الآخر، مصحوباً بتبديل مستمر ومجهد للسياق البرمجي. - [13:53](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=833s) تم بناء بيئة اختبار موحدة زُوّدت بوكيل ذكاء اصطناعي لتوسيع مسارات التطبيق واكتشاف الأعطال وحلها ذاتياً لإنشاء خارطة طريق استكشافية. - [15:32](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=932s) أظهرت مراجعة بشرية لنحو 200 تعديل أنتجها الوكيل أن 50% منها نظيف وجاهز للدمج، بينما تطلبت 10% جلسات معمارية عميقة. - [18:40](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=1120s) حُدد نطاق 'الدعم التجريبي لـ Ractor' للتركيز على مسارات السقالات (scaffold) الأساسية وتأجيل ميزات معقدة مثل Action Cable والتحميل الكسول. - [20:33](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=1233s) ابتكر الفريق نمط 'فحص العزل' (isolation check) لجمع تحذيرات الانتهاكات دون إيقاف التنفيذ، وتم ربطه ببناء ليلي يفحص نحو 200 مسار تلقائياً. - [22:15](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=1335s) خفّض تجميد الثوابت وحدها ما يقارب 30% من أخطاء العزل، بينما تم اعتماد نمط 'تحديث النسخة المقروءة' لضبط سمات الفئات في Active Record بأمان. - [24:25](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=1465s) عمليات الإدخال والإخراج ومجمعات الاتصال غير آمنة لـ Ractors حالياً، مما فرض استخدام مكتبة ractor-dispatch لتنفيذ الاستعلامات عبر الـ Ractor الرئيسي. - [26:13](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=1573s) يعد تمرير الاستعلامات إلى الـ Ractor الرئيسي السبب الأساسي لارتفاع زمن الاستجابة (latency)، والحل النهائي يتطلب اتصالاً مباشراً من راكتور الطلب. - [28:15](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=1695s) وفّر الفريق واجهة Rails.application.reactorize التجريبية وقوالب جاهزة تتيح لمجتمع Ruby اختبار وتطوير مشاريعهم ومكتباتهم على خوادم مثل Cougar وKeno.

## Detailed walkthrough ### [00:10](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=10s) مقدمة والتعريف بالمتحدث وخطة المحاضرة

بدأ أندرو نوفوسيلاك (Andrew Novoselac) كلمته بالترحيب بالحضور وتقديم نفسه بأسلوب ودود؛ فهو مطوّر يعمل في فريق البنية التحتية لـ Ruby on Rails في شركة Shopify، ويقيم في مدينة هاميلتون بمقاطعة أونتاريو الكندية. أوضح أندرو أنه يعمل في تطوير تطبيقات Rails منذ عام 2018، مشيراً بابتسامة إلى أن هذه هي أول مشاركة له كمتحدث في مؤتمر تقني على الإطلاق، وطلب من الجمهور تشجيعه والتمني له بالتوفيق بقوله: "أرجو منكم الترحيب بي وتمنياتي لي بالتوفيق".

حدّد أندرو بعد ذلك المحاور الأساسية لمحاضرته التي تدور حول جعل إطار عمل Rails متوافقاً وآمناً مع راكتور (Ractor-safe): - استعراض مفهوم خادم الويب القائم على Ractors ودوافع فريق Shopify لخوض هذه التجربة ومحاولة حل مشكلات الكفاءة. - تفكيك أسباب صعوبة جعل إطار عمل ضخم مثل Rails آمناً للعمل مع Ractor، وما الذي تعنيه هذه العملية على المستوى التقني. - شرح كيفية رسم خريطة شاملة لحجم المشكلة ونطاقها بالاعتماد على حلقة وكيل ذكاء اصطناعي (AI agent loop). - استعراض التعديلات البرمجية التي تم تقديمها ودمجها فعلياً في Rails (Upstreaming)، وتوضيح الوضع الحالي والخطوات القادمة في المستقبل.

---

[01:12](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=72s) مقارنة آليات التزامن في Ruby: العمليات، الخيوط، وRactors

انتقل أندرو لتوضيح ماهية Ractors، واصفاً إياها بأنها وحدات بناء أولية للتزامن (concurrency primitives) تتيح التنفيذ البرمجي المتوازي (parallel execution) الحقيقي داخل عملية نظام واحدة (single process). ولتوضيح قيمتها المضافة، عقد مقارنة منهجية بين Ractors وأدوات التزامن التقليدية المتاحة في لغة Ruby، وهي العمليات (Processes) والخيوط (Threads):

1. **العمليات (Processes):** تُشغّل بيئة Ruby الكود داخل عمليات نظام. العمليات متوازية تماماً وقادرة على تشغيل كود Ruby في الوقت نفسه (مثل فتح نافذتين في الطرفية وتشغيل جلستي `rails console` مستقلتين). لكن عيبها الأساسي هو العزل التام للذاكرة وعدم مشاركتها؛ فكل عملية تُحمّل الكود الخاص بها وتحتفظ بمساحة كائنات (object space) منفصلة. 2. **الخيوط (Threads):** يمكن تشغيل خيط واحد أو خيوط متعددة داخل نفس العملية ومشاركة الذاكرة وتحميل الكود مرة واحدة فقط لتصل إليه جميع الخيوط. لكن المشكلة تكمن في غياب التوازي الحقيقي بسبب قفل الآلة الافتراضية العام (GVL - Global VM Lock)؛ حيث يستحوذ خيط واحد فقط على GVL لتنفيذ كود Ruby بينما تظل بقية الخيوط في حالة انتظار وتوقف (suspended). 3. **الراكتورات (Ractors):** تجمع بين أفضل مزايا العمليات والخيوط؛ فهي تسمح بتنفيذ الكود بالتوازي داخل عملية واحدة لأن لكل وحدة Ractor قفل GVL خاصاً بها ومستقلاً عن الأخرى، وتتشارك في الوقت نفسه نفس الذاكرة ونفس الكود والكائنات.

ضرب أندرو مثالاً توضيحياً بحساب خوارزمية فيبوناتشي سريعة (Fast Fibonacci) تستغرق 100 مللي ثانية للعملية الواحدة، مع افتراض الرغبة في تنفيذها 3 مرات: - **باستخدام الخيوط:** عند توزيع الحسابات على ثلاثة خيوط، ينفذ الخيط الأول عمليته خلال أول 100 مللي ثانية بينما ينتظر الخيطان الآخران، ثم ينفذ الخيط الثاني، يليه الخيط الثالث. النتيجة أن البرنامج يستغرق 300 مللي ثانية إجمالاً، لأن خيطاً واحداً فقط ينفذ كود Ruby في اللحظة ذاتها. - **باستخدام Ractors:** تمتلك كل وحدة Ractor قفل GVL خاصاً بها، مما يمكّن الوحدات الثلاث من إتمام العمليات الحسابية بالتوازي في الوقت عينه، لينتهي التنفيذ بالكامل خلال 100 مللي ثانية فقط بدلاً من 300.

أشار أندرو إلى خلفية تاريخية سريعة؛ إذ ظهرت Ractors كميزة تجريبية لأول مرة مع إطلاق Ruby 3.0 في عام 2020، وبفضل جهود مهندسي Shopify ومجتمع Ruby الأوسع، شهدت تحسينات جذرية في Ruby 4.0 مع وعود بالمزيد في Ruby 4.1، لتصل إلى مرحلة النضج والجاهزية للاختبار الحقيقي في بيئات الإنتاج (Production).

```mermaid flowchart TD accTitle: مقارنة نماذج التزامن في روبي accDescr: مخطط يوضح الفرق بين العمليات والخيوط والراكتور من حيث التوازي ومشاركة الذاكرة

subgraph Processes["العمليات (Processes)"] P1["عملية مستقلة 1<br/>ذاكرة معزولة"] P2["عملية مستقلة 2<br/>ذاكرة معزولة"] P1 -.->|"توازي كامل / لا مشاركة ذاكرة"| P2 end

subgraph Threads["الخيوط (Threads)"] T_MEM["ذاكرة مشتركة واحدة"] T1["خيط 1 (يمتلك GVL)"] T2["خيط 2 (معلق ينتظر GVL)"] T_MEM --- T1 T_MEM --- T2 end

subgraph Ractors["الراكتورات (Ractors)"] R_MEM["ذاكرة مشتركة موحدة"] R1["Ractor 1 (GVL مستقل)"] R2["Ractor 2 (GVL مستقل)"] R_MEM === R1 R_MEM === R2 end ```

---

[04:06](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=246s) فكرة خادم الويب القائم على Ractor وتجربة الأداء مع تطبيق Writebook

انتقل الحديث إلى التطبيق العملي للتقنية داخل Shopify عبر بناء خادم ويب تجريبي يعتمد على Ractors. استعرض أندرو المعضلة الهندسية في خوادم الويب الحالية: - **الخوادم متعددة الخيوط (Multithreaded):** تعمل بعملية واحدة وعدة خيوط، وتضطر لزيادة الخيوط لخدمة طلبات متزامنة أكثر، مما يؤدي إلى زيادة زمن الاستجابة (latency) بسبب تناوب الخيوط واصطفافها في طوابير الانتظار لنيل الـ GVL. - **الخوادم متعددة العمليات (Preforking):** الحل التقليدي المعتمد تاريخياً في Shopify والمجتمع، وفيه تُنشأ عملية رئيسية تتفرع لعدة عمليات فرعية تخدم الطلبات بالتوازي. ورغم وجود تقنية "النسخ عند الكتابة" (Copy-on-Write) على مستوى نظام التشغيل لمشاركة بعض الصفحات في البداية، إلا أن صفحات الذاكرة تتباعد وتفسد مع استمرار العمل، مما يجعل العمليات معزولة تماماً. وبناءً عليه، تعني زيادة التزامن زيادة عدد العمليات، مما يتسبب في استهلاك ضخم للذاكرة.

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

لاختبار هذه الفرضية، بنى الفريق تجربة باستخدام تطبيق Writebook (تطبيق التدوين وحفظ الدفاتر مفتوح المصدر من Basecamp): - قاموا بجعل جزء صغير من التطبيق آمناً لـ Ractor وربطه بخادم ويب تجريبي يُدعى **Keno** (يعمل بعملية واحدة و9 معالجات Ractor)، وقارنوا أدائه بخادم **Puma** الكلاسيكي (مضبوط على 9 عمليات). - **الذاكرة:** حقق خادم Ractor توفيراً هائلاً؛ حيث استهلك خادم Puma قرابة 7 أضعاف الذاكرة مقارنة بـ Keno. - **زمن الاستجابة (Latency):** سُجلت زيادة بنسبة 25% في زمن الاستجابة لصالح Puma (أي أن Ractor كان أبطأ بنسبة 25%). - ترك أندرو سبب زيادة زمن الاستجابة مؤقتاً "كتمرين للمشاهد ليفكر في سببه" قبل أن يعود لشرحه لاحقاً في المحاضرة، داعياً الجمهور للاطلاع على المقال التقني المنشور على مدونة Shopify الهندسية والذي يوثق كافة تفاصيل وأرقام هذه التجربة.

---

[07:27](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=447s) ما المقصود بـ "Ractor-safe" وتحدي التجميد العميق للبيانات

طرح أندرو السؤال الجوهري الذي قد يتبادر لذهن أي مهندس متشكك: "ما المشكلة إذن؟ ما الذي يجعل هذا العمل صعباً إلى هذا الحد؟" وأجاب بالاعتراف بأنه استخدم مصطلح "Ractor-safe" دون تعريفه بدقة، منتقلاً لتفكيك المعنى الداخلي لأمان Ractor في بيئة Ruby.

تتشارك وحدات Ractor الذاكرة بالفعل، لكن Ruby تفرض قيداً عزل صارماً: **أي كائن يتم مشاركته بين وحدات Ractor يجب أن يكون مُجمّداً تجميداً عميقاً (Deeply Frozen)**. لا يكفي تجميد الكائن الخارجي فقط (`freeze`)، بل يجب تجميد كافة متغيرات الحالة ومثيلاتها (instance variables)، ومتغيرات الكائنات التابعة لها وصولاً إلى آخر عقدة في شجرة الكائن بالكامل.

```ruby # مثال يوضح أخطاء العزل وضرورة التجميد العميق:

# 1. جدول تجزئة قابل للتعديل يسبب خطأ عزل config = { key: "value" } Ractor.new { config[:key] } # => Ractor::IsolationError (can not access non-shareable objects)

# 2. تجميد سطحي غير كافٍ إذا احتوى كائنات قابلة للتعديل config = { key: ["bar"] }.freeze Ractor.new { config[:key] } # => Ractor::IsolationError (المصفوفة داخل التجزئة لا تزال قابلة للتعديل)

# 3. الحل: التجميد العميق لجعل الكائن قابلاً للمشاركة config = { key: ["bar"] } Ractor.make_shareable(config) Ractor.new { config[:key] } # يعمل بنجاح وبأمان تام ```

أوضح أندرو الخطوات عبر المثال البرمجي: - إذا كان هناك ملف تهيئة في صورة جدول تجزئة (Hash)، وحاول Ractor جديد الوصول إليه مباشرة من Ractor الرئيسي المنشئ له، ستلقي لغة Ruby خطأ عزل (`Ractor::IsolationError`) لأن الـ Hash قابل للتعديل (mutable). - تجميد الـ Hash فقط يحل المشكلة جزئياً إذا كانت قيمه بدائية؛ ولكن إذا احتوى على كائنات مركبة قابلة للتعديل (مثل مصفوفة بداخلها نصوص)، فإن محاولة الوصول إليها ستُسفر عن الخطأ ذاته لأن المصفوفة الداخلية لم تُجمد. - القاعدة تفرض تجميد كل شيء؛ ولتسهيل ذلك توفر Ruby الدالة المساعدة `Ractor.make_shareable`. - اختتم أندرو هذا الجزء بالإشارة إلى الكلمة الافتتاحية التي قدمها آرون باترسون (Aaron Patterson) في مؤتمر العام السابق، والتي شرح فيها أساسيات كائنات Ractor وآليات جعل العناصر قابلة للمشاركة بالتفصيل، ناصحاً الحضور بالرجوع إليها لفهم الأسس النظرية التحتية لمنظومة المشاركة.

[09:22](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=562s) محاكاة جعل تطبيق Rails آمنًا مع Ractor وسلسلة الأخطاء المتتابعة

يوضح أندرو نوفوسيلاك ما يعنيه عمليًا جعل إطار عمل Rails متوافقًا وآمنًا للاستخدام مع ميزة Ractor في لغة روبي (Ractor-safe). المفهوم الأساسي في جوهره يبدو مباشرًا للغاية: يبدأ بتشغيل التطبيق، ثم استدعاء دالة `Ractor.make_shareable` على كائن تطبيق Rails نفسه—وهو الكائن المسؤول فعليًا عن تلقي الطلبات والاستجابة لها—وبعد ذلك، يتم إنشاء Ractor جديد واستدعاء التطبيق بداخله لمعالجة معلومات الطلب. ولكن للإجابة عن التساؤل البديهي: "ما مدى صعوبة ذلك؟"، يفضل أندرو استعراض ما يحدث خطوة بخطوة بدلًا من الاكتفاء بالشرح النظري. ورغم تحذيرات زملائه الشديدة من إجراء عرض توضيحي مباشر (Live Demo) على المسرح تجنبًا للمفاجآت غير السارة، فإنه يدعو الحضور إلى تخيل إجراء العرض مباشرة: إنشاء تطبيق Rails جديد، وفتح سطر أوامر وحدة التحكم (Console)، واستدعاء دالة `Ractor.make_shareable`، ومراقبة النتيجة.

بمجرد تنفيذ هذا الاستدعاء، تنهار التجربة سريعًا ويظهر الخطأ الأول: > "خطأ: لا يمكن مشاركة الإجراء `self` من ملف `rails/initializable.rb` في السطر 44."

عند تفحص الكود المسبب، يتبين أن تطبيقات Rails ومحركاتها (Rails engines) تعرّف مهيئات (Initializers) تُخزن داخل بنية بيانات تستخدم جداول تجزئة (Hashes). تحتوي هذه الجداول على إجراءات برمجية (Procs) افتراضية؛ بحيث إذا طُلب منها مفتاح غير موجود، يقوم الـ Proc تلقائيًا بتعيين قيمة فارغة لذلك المفتاح. المشكلة الجوهرية تكمن في أن هذا الـ Proc يرتبط ضمنيًا بـ `self`، ولكي يصبح الكود آمنًا وقابلًا للمشاركة في بيئة Ractor، يجب أن يكون كل كائن يشير إليه الإجراء آمنًا وغير قابل للتعديل أيضًا. لكن التغلب على هذه العقبة ممكن منطقيًا: فبمجرد إقلاع تطبيق Rails، تكون كافة المُهيئات قد حُمّلت ونُفّذت بالفعل، ولا يُفترض بالتطبيق إنشاء مهيئات جديدة في خضم معالجة طلبات الويب—ويعلق أندرو ساخرًا بأنه "رأى بعض الأمور الغريبة في تطبيقات Rails، لكن نأمل ألا نُنشئ مُهيئات أثناء معالجة الطلبات". بالتالي، يمكن ببساطة التخلص من هذا الإجراء الافتراضي وتجميد (freeze) المجموعة بالكامل لتجاوز العقبة الأولى.

عند إعادة المحاولة واستدعاء `make_shareable` مجددًا، يظهر خطأ جديد على الفور: `undefined method freeze for Concurrent::Map`. خرائط `Concurrent::Map` غير قابلة للتجميد في روبي، وبالتالي تُعد غير آمنة في بيئة Ractor. العقبة الإضافية هنا كانت غياب السياق؛ إذ لا تُظهر رسالة الخطأ سطر الكود أو الكائن الذي يحتوي على هذه الخريطة. ولمعالجة هذا القصور في رسائل أخطاء Ractor غير المرضية، قام فريق أندرو في Shopify بتقديم تصحيحات (Patches) في شجرة تطوير لغة روبي (مستهدفة الإصدارات القادمة)، بحيث تُظهر رسالة الخطأ المسار الهرمي للكائن ومتغيرات الحالة (Instance variables) صعودًا حتى قمة شجرة الكائنات. وباستخدام هذا التتبع، تبيّن أن مصدر الخريطة يعود إلى مكتبة `Solid Cache`. تعقيد المشكلة هنا يرجع إلى أن `Solid Cache` ليست جزءًا مدمجًا في نواة Rails، بل جوهرة (Gem) مستقلة تعتمد بدورها على `Active Record`، مما يطرح معضلة معقدة حول كيفية جعل جوهرة خارجية آمنة مع Ractor قبل أن يصبح الإطار الأساسي نفسه آمنًا.

- **الخطأ الأول:** فشل مشاركة الـ Proc في `rails/initializable.rb:44` بسبب ارتباطه بكائن `self`. - **حل المشكلة الأولى:** إسقاط الـ Proc الافتراضي وتجميد جدول التجزئة بعد اكتمال مرحلة الإقلاع. - **الخطأ الثاني:** عدم قابلية `Concurrent::Map` للتجميد داخل جوهرة `Solid Cache`. - **تحسين رسائل روبي:** مساهمات برمجية من فريق Shopify لإظهار التسلسل الهرمي للكائنات في أخطاء Ractor. - **الخطأ الثالث:** خطأ جديد ينبثق من `Action Cable` بمجرد الالتفاف حول المشاكل السابقة.

---

[12:40](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=760s) تحديات الحل اليدوي وعصر "البرمجة الكلاسيكية"

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

يُضاف إلى ذلك الإرهاق الذهني الناجم عن التبديل المستمر للسياق (Context Switching). ففي غضون دقائق معدودة، ينتقل المطور من التعامل مع مهيئات إقلاع Rails، إلى مكتبة تخزين مؤقت خارجية (`Solid Cache`)، ثم مباشرة إلى نظام اتصالات الويب الحية (`Action Cable`). ويجد المهندس نفسه مجبرًا على القفز عبر مكونات الإطار المعقد بترتيب عشوائي يفرضه مسار استدعاء الأخطاء، وكل هذا العناء يحدث حتى قبل الوصول إلى التحديات البرمجية الحقيقية؛ أي مرحلة معالجة طلبات الويب الفعلية وما تتطلبه من الوصول إلى قواعد البيانات، وعرض القوالب (Rendering)، وتسجيل البيانات (Logging)، وإدارة الذاكرة المؤقتة.

يوضح أندرو أن فريقه في Shopify حاول في البداية خوض هذه المهمة يدويًا بالكامل، فيما وصفه ديفيد هاميلتون بـ "العصر القديم للبرمجة"، ويفضل أندرو تسميته "البرمجة الكلاسيكية". ولكن مع بطء التقدم الشديد وتكرار العقبات غير المتوقعة، بات واضحًا للجميع أن اتباع هذا النهج التقليدي لن يجدي نفعًا، ولا بد من البحث عن أسلوب جديد ومختلف جذريًا.

---

[13:53](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=833s) الاستعانة بوكلاء الذكاء الاصطناعي وبناء بيئة الاختبار (Harness)

مع التطور المتسارع في قدرات وكلاء الذكاء الاصطناعي (AI Agents)، طرح الفريق فكرة الاعتماد على وكيل ذكي للمساعدة في رسم هذه الخارطة المعقدة. الميزة الأكبر لوكلاء الذكاء الاصطناعي—بحسب تعبير أندرو المازح—هي أنهم "لا يهتمون إلا بالمال ولا يتعبون أبدًا"؛ فما دمت تزود النظام بوحدات الحوسبة والرموز (Tokens)، فلن يطلب استراحة غداء، ولن يشعر بالملل أو تشتت الانتباه، بل سيواصل تكرار المحاولات بلا كلل.

لبناء هذه المنظومة، أنشأ الفريق ما أطلقوا عليه "تسخير المستودع" (Repo Harness). وهو مستودع برمجي موحد ومغلق يحتوي على كافة التبعيات الضرورية: شجرة كود Ruby، ومكتبة Rack، ومستودع Rails، إضافة إلى تطبيق وهمي (Dummy App) مرتبط بهذه التبعيات. زُوّد الوكيل بمجموعة من المهارات والأدوات البرمجية، مثل القدرة على تشغيل الاختبارات، وإعادة بناء لغة روبي من المصدر إذا أدخل تعديلات عليها، وتحديث بيئة التطوير لنفسه تلقائيًا.

```mermaid flowchart TD accTitle: دورة عمل وكيل الذكاء الاصطناعي لتأمين Rails مع Ractors accDescr: يوضح الرسم التكرار الآلي للوكيل عبر أربع مراحل من التحميل حتى توسيع الوظائف داخل بيئة المستودع الموحد.

subgraph Harness["بيئة المستودع الموحد (Repo Harness)"] Deps["تبعيات Ruby + Rack + Rails + Dummy App"] Tools["أدوات الوكيل: تشغيل الاختبارات وإعادة بناء Ruby"] end

subgraph Loop["حلقة التكرار المستمرة (Agent Loop)"] Step1["1. تعديل الكود لجعل التطبيق قابلاً للمشاركة (make_shareable)"] Step2["2. معالجة الطلبات وإرجاع استجابة 200 OK عبر Ractor"] Step3["3. توليد مسارات جديدة وكسر بيئة Ractor عمدًا"] Step4["4. تصحيح الأعطال وجعل المسارات الجديدة Ractor-safe"] end

Harness --> Step1 Step1 --> Step2 Step2 --> Step3 Step3 --> Step4 Step4 -->|"تكرار لا نهائي"| Step3 ```

أما خطة العمل التي كُلف بها الوكيل، فكانت تتلخص في حلقة تكرارية واضحة: 1. الاستمرار في تجربة التعديلات حتى ينجح التطبيق في استدعاء `Ractor.make_shareable`. 2. مواصلة التكرار حتى يتمكن التطبيق من الرد على طلب HTTP باستجابة ناجحة `200 OK` من داخل Ractor. 3. الشروع في إضافة وظائف ومسارات جديدة تكسر التوافق مع Ractor، ثم ابتكار حلول برمجية لإصلاحها وجعلها تعمل. 4. الاستمرار في هذه الدورة التوسعية والتصحيحية إلى ما لا نهاية حتى يصدر أمر بالتوقف.

---

[15:32](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=932s) نتائج التجربة: رسم خارطة طريق لأمان الـ Ractor

أسفرت التجربة عن نتائج مذهلة تجاوزت التوقعات؛ حيث استخرج الوكيل تقريرًا تفصيليًا يوضح أن التطبيق الوهمي بات يحتوي على **169 مسارًا برمجياً (Routes)** تعمل بالكامل داخل Ractors، محققًا تغطية بلغت حوالي **67% من قاعدة كود إطار عمل Rails**، وموزعة بدقة عبر مختلف مكونات النظام. وعلى الصعيد التشغيلي، كلف هذا التشغيل ما يقارب **2,000 دولار** من أرصدة نموذج Claude 3 Opus (أفضل نموذج متوفر آنذاك)، وتطلب حوالي أسبوع واحد فقط من العمل الهندسي البشري لإعداد البيئة ومراقبتها. أجرى الفريق بعد ذلك دورات إضافية للتحقق من إمكانية إعادة إنتاج النتائج ولتحسين بعض الحلول المقترحة.

وسط أجواء الاحتفال بإنجاز المهمة—وعرض شعار "Toronto Ractors" التورنتوي الساخر الذي يعتمده مهندسو Shopify كشعار غير رسمي لمشروع Ractor—تطرق أندرو إلى السؤال الحتمي الذي يطرحه المهندسون المنتمون لنادي "أنا ما زلت أقرأ الكود": هل راجع أحد هذا الكود المولد آليًا بالفعل؟ يؤكد أندرو أنه قضى أسبوعين كاملين في قراءة كل سطر كود أنتجه الوكيل، حيث راجع النموذج النهائي الذي تضمن حوالي **200 تعديل داخل إطار عمل Rails**، تركز معظمها في جوهر النظام: `Action View`، و`Active Record`، و`Action Pack`.

| تصنيف التعديلات | النسبة | التقييم الهندسي وطبيعة التعديل | |:--- |:--- |:--- | | **تعديلات نظيفة وبسيطة** | 50% | حلول واضحة، تبدو ممتازة وجاهزة للدمج (Merge) المباشر في الإطار. | | **حلول في الاتجاه الصحيح** | 40% | أفكار سليمة تمامًا تحتاج فقط لتوجيه بشري طفيف أو تنظيف برمجي قبل الدمج. | | **مسائل معمارية وتصميمية** | 10% | أجزاء معقدة تتطلب جلسات تصميم مخصصة بين البشر لتحديد المعمارية المناسبة لـ Rails. |

في المقابل، لم يخلُ عمل الوكيل من عيوب تعكس طبيعته الآلية؛ فلم يتردد في كتابة دوال ضخمة تتجاوز 5,000 سطر، أو تكرار نفس النمط البرمجي عشرات المرات عبر الكود بدلًا من صياغة واجهة برمجية (API) مجردة وأنيقة—وهي القيمة التي يحرص عليها مجتمع Rails بشدة. كما لجأ الوكيل أحيانًا إلى عزل أخطاء Ractor وتجاوزها بأساليب التفافية قسرية. لكن أندرو يشدد على أن الهدف الأساسي لم يكن الحصول على كود مثالي جاهز للإنتاج فورًا، بل توفير **خارطة طريق استكشافية** لمشكلة ضخمة كان يُعتقد أنها ستستغرق عامًا كاملًا من البحث البشري المضني لفهم أبعادها، بينما وفر الوكيل تصنيفًا شاملاً لنطاق العمل في غضون أسبوعين فقط.

---

[18:40](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=1120s) المرحلة الأولى: تحديد نطاق الدعم التجريبي (Experimental Ractor Support)

بعد امتلاك النموذج الأولي والخارطة الشاملة، انتقل الفريق إلى التفكير في الخطوات العملية للمساهمة في النسخة الرئيسية من Rails (Upstreaming). وبدلًا من محاولة دمج هذا الحجم الهائل من التغييرات دفعة واحدة، استقر الرأي على استخلاص نطاق عملي ومحدد يمثل المرحلة الأولى، أُطلق عليه "الدعم التجريبي لـ Ractor" (Experimental Ractor Support).

يهدف هذا النطاق الأولي إلى تمكين المطور من إنجاز المهام الأساسية التالية بنجاح تام: - إنشاء تطبيق جديد تمامًا عبر الأمر المعتاد `rails new`. - إنشاء مسارات ونماذج قياسية باستخدام السقالات البرمجية (`scaffold`). - جعل تطبيق Rails قابلاً للمشاركة بالكامل عبر `Ractor.make_shareable(Rails.application)`. - تشغيل واستجابة كافة هذه المسارات المولدة من داخل كائنات Ractor مستقلة.

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

[19:42](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=1182s) حدود النطاق والابتعاد عن فخ حلقة الذكاء الاصطناعي

يوضح أندرو نوفوسيلاك أن الفريق قرر حصر النطاق بدقة في هذه المرحلة؛ إذ لم يتم تعديل Action Cable، أو معالجة المهام الخلفية، أو التبعيات الخارجية مثل Solid Cache، كما تُرك وضع التطوير (development mode) دون مساس بسبب اعتماده العميق على التحميل الكسول (lazy loading). وعندما حان وقت نقل التعديلات من النموذج الأولي العملاق وغير المنظم إلى الفرع الرئيسي لـ Rails، واجه الفريق معضلة تحديد ما يحتاجونه فعليًا للدمج في المصدر الرئيسي.

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

[20:33](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=1233s) ابتكار فحص العزل (Isolation Check) وتتبع الأخطاء يوميًا

لتحقيق الدقة المطلوبة، ابتكر الفريق مفهوم "فحص العزل" (isolation check) في الـ Ractor. هذا النمط هو Ractor خاص ومُعدّل لا يملك خصائص التوازي الحقيقية، لأنه بدلًا من إيقاف البرنامج وإلقاء خطأ عزل صارم بمجرد لمس حالة غير آمنة، يقوم بإصدار تحذيرات واستكمال التنفيذ. هذا التغيير البسيط يسمح بجمع وحصر جميع انتهاكات العزل التي تحدث أثناء دورة حياة الطلب الواحد كاملة دون أن يتعطل السيرفر عند أول عقبة. فعلى سبيل المثال، إذا تم استدعاء ثابت مثل `foo` ثلاث مرات، يتلقى المطور ثلاثة تحذيرات مفصلة ثم يُطبع "Hello world" كالمعتاد.

تم رفع هذا المقترح إلى نظام تتبع الأخطاء والميزات الرسمي للغة روبي، ويأمل الفريق أن يصبح جزءًا أساسيًا من روبي 4.1. ولبناء مسار عملي، ربط الفريق هذه الميزة ببناء تجريبي ليلي (nightly build) يقوم بسحب أحدث تغييرات Rails، وتشغيل ما يقارب 200 مسار طلب فريد، وجمع الانتهاكات وتصنيفها تلقائيًا وفق مكان حدوثها في الكود وتتبع الأخطاء (stack traces). وقد منحهم هذا الجمع بين النموذج الأولي للذكاء الاصطناعي (الذي قدّم أنماط الحلول) وفحص العزل الليلي (الذي حدد المشاكل الحية يوميًا) رؤية كاملة للانطلاق في العمل الفعلي.

```mermaid flowchart TD accTitle: خط أنابيب فحص العزل الليلي لـ Rails accDescr: يوضح الرسم كيفية سحب الكود وفحص المسارات عبر راكتور فحص العزل لجمع التحذيرات وتصنيفها.

subgraph NightlyBuild ["البناء التجريبي الليلي"] A["سحب آخر تحديث لـ Rails"] --> B["تهيئة التطبيق وتوليد المسارات (~200 مسار)"] B --> C["تنفيذ الطلبات داخل راكتور فحص العزل"] end

subgraph DiagnosticOutput ["النتائج والتشخيص"] C -->|"إصدار تحذيرات دون إيقاف التنفيذ"| D["تجميع أخطاء العزل"] D --> E["تصنيف الأخطاء حسب الملف وتتبع الكود"] end ```

[22:15](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=1335s) تدفق طلبات السحب وأنماط الإصلاح: الثوابت وحالة الفئات

خلال أشهر الصيف، أرسل فريق البنية التحتية في شوبيفاي أكثر من 100 طلب سحب (Pull Request) إلى Rails لتعزيز أمان الـ Ractor، وتراوحت تلك التعديلات بين البسيطة والمعقدة:

- **تجميد الثوابت (Freezing Constants):** كانت البداية مع أسهل المشاكل، حيث احتوى Rails على العديد من الثوابت المعرفة كمصفوفات أو جداول تجزئة قابلة للتعديل دون داعٍ حقيقي، مما يسبب أخطاء عزل فورية عند الوصول إليها من Ractor آخر. أدى تجميد هذه الثوابت عبر الكود واستخدام قواعد RuboCop المخصصة إلى خفض ما يقرب من 30% من إجمالي الأخطاء فورًا. - **سمات الفئات ونمط تحديث النسخة المقروءة (Copy-on-Write Pattern):** تمتلك نماذج Active Record سمات مثل مصفوفات الحقول المخصصة للقراءة فقط. اقترح وكيل الذكاء الاصطناعي في البداية دالة ضخمة تتجاوز 5000 سطر تمر على التطبيق بالكامل لتجميد كل شيء قبل الإغلاق، لكن الفريق رفضها لصعوبة إدارتها ولأنها تخلق حالة يدوية هشة تتطلب تذكر استدعائها. - **التنفيذ العملي للنمط:** اعتمد الفريق بديلًا أسماه نمط "تحديث النسخة المقروءة"؛ حيث تكون المصفوفات مجمّدة افتراضيًا، وعند الرغبة في إضافة عناصر، تؤخذ نسخة منها، تُضاف العناصر، ثم تُجمّد النسخة الجديدة ويُعاد تعيينها للسمة، مما يضمن أمانها عبر كل مراحل دورة حياة التطبيق (وهو نمط فصله زميله هارلي في مقال تقني).

[24:25](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=1465s) التحدي المعقد: الوصول لقاعدة البيانات وعمليات الإدخال/الإخراج

شكّل الوصول لقاعدة البيانات العقبة الكبرى لأن عمليات الإدخال والإخراج (I/O) غير آمنة للمفاعلات بطبيعتها ولا يمكنها عبور حدود الـ Ractor مباشرة، فضلاً عن أن مجمعات الاتصال (connection pools) هي كائنات متغيرة الحالة تتبع من يستأجر الاتصالات في أي لحظة. لحل هذه الأزمة مؤقتًا، استخدم الفريق جوهرة تُدعى `ractor-dispatch` تسمح بتمرير المهام غير الآمنة لتُنفّذ داخل الـ Ractor الرئيسي ثم إعادة النتائج إلى راكتور الطلب.

```mermaid flowchart LR accTitle: دورة حياة طلب قاعدة البيانات عبر Ractor Dispatch accDescr: توضح الخطوات انتقال العمل من راكتور الطلب إلى الراكتور الرئيسي للتعامل مع قاعدة البيانات ثم العودة.

subgraph RequestRactor ["راكتور معالجة الطلب"] Req1["تنفيذ البرمجيات الوسيطة"] --> Req2["بناء استعلام SQL"] Req3["تهيئة نموذج Active Record"] --> Req4["عرض صفحة HTML"] end

subgraph MainRactor ["الراكتور الرئيسي"] MainExec["تنفيذ استعلام SQL والاتصال بقاعدة البيانات"] end

Req2 -->|"تمرير الاستعلام (Dispatch)"| MainExec MainExec -->|"إعادة النتائج المجمّدة"| Req3 ```

يتم تنفيذ معالجة الطلب، والبرمجيات الوسيطة (middleware)، وبناء استعلام الـ SQL على راكتور الطلب، ولكن لحظة تنفيذ الاستعلام الفعلي، يُرسل العمل إلى الـ Ractor الرئيسي الذي يمتلك الاتصال بقاعدة البيانات، ومن ثم تُعاد النتائج إلى راكتور الطلب لتهيئة الكائنات وعرض الـ HTML.

[26:13](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=1573s) ضريبة التأخير (Latency) والحلول المستقبلية

يكشف هذا النمط بوضوح سبب زيادة زمن الاستجابة (latency) عند استخدام المفاعلات؛ فالـ Ractor الرئيسي يعمل كخيط تنفيذ أحادي لا يستطيع معالجة سوى استعلام واحد في الوقت ذاته. إذا وصل طلبان (GET و POST) في الوقت نفسه، سيضطر أحدهما للانتظار حتى ينتهي الـ Ractor الرئيسي من استعلام الطلب الأول، مما يُحدث حظرًا وتأخيرًا متراكمًا، إضافة إلى تكلفة نقل الرسائل ومشاركتها بين المفاعلات نفسها (inter-ractor communication).

- **الرؤية المستقبلية:** الهدف النهائي هو تشغيل 100% من الكود على راكتور الطلبات، وأن تمتلك الاتصالات مفاعلات خاصة بها يستطيع راكتور الطلب فحصها والتحكم بها مباشرة، لكن هذا يتطلب إعادة هيكلة جذرية داخل Rails. - **عوائق إضافية:** وجود حالات كسولة في Active Record تُهيأ فقط عند أول اتصال بقاعدة البيانات ويجب ضبطها على الـ Ractor الرئيسي، بالإضافة إلى مكتبات غير متوافقة مع الـ Ractors حتى الآن، وعلى رأسها مكتبة `Nokogiri`.

[28:15](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=1695s) كيفية تجربة المفاعلات في Rails محليًا

أتاح الفريق واجهة جديدة للبدء في الاختبار تسمى `Rails.application.reactorize`، والتي تدمج كافة الخطوات التمهيدية الإلزامية قبل تجميد التطبيق وجعله قابلاً للمشاركة بين المفاعلات (shareable). ويُنبه أندرو إلى أن استدعاء هذه الدالة يطبع تحذيرًا صريحًا بأن دعم المفاعلات لا يزال تجريبيًا وعرضة للتغيير بالكامل، بما في ذلك اسم التابع نفسه ("لذا لا تعتاد عليه").

يمكن للمطورين تجربة هذه الميزة عمليًا عبر استخدام خوادم ويب مبنية على الـ Ractors؛ حيث رشح خادم `Cougar` لكونه بسيطًا وخفيفًا للغاية ويسهل قراءة كامل كوده البرمجي، وخادم `Kino` الذي يتميز بثرائه البرمجي ودعمه لميزات أوسع، إلى جانب توفير قالب (template) جاهز لبدء المشاريع واختبار السلوك بأنفسهم.

[29:00](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=1740s) قالب Rails المهيأ لـ Ractor وتجربة الخادم المباشرة

يشرح أندرو نوفوسيلاك كيفية البدء العملي بتجربة هذه التقنية، مشيرًا إلى توفير قالب لتطبيق Rails مهيأ بالكامل ليعمل بتوافق مع Ractor. يتضمن هذا القالب إعدادات خاصة ومحددة، مثل تخطي حزم Solid Gems الافتراضية، وتفعيل بعض الميزات الضرورية الأخرى لضمان تشغيل دعم Ractor بشكل صحيح. ولتسهيل الوصول إلى هذا السكربت، عُرض رمز استجابة سريعة (QR code) على الشاشة يحتوي على الرابط المباشر للقالب، والذي وصفه بأنه طويل نوعًا ما. وبمجرد تشغيل هذا السكربت، يبدأ خادم الويب بالعمل، وعند إرسال طلبات حقيقية إليه، يتم معالجتها وتقديم الاستجابة مباشرة عبر الـ Ractor الرئيسي، وهو ما يمثل خطوة مثيرة وملموسة للغاية في هذا المسار.

ولم يخلُ هذا الطرح من لمسة فكاهية وتحذير أمني في آنٍ واحد؛ حيث حثّ الحضور بابتسامة على قراءة محتوى القالب وفحصه جيدًا قبل تشغيله على أجهزتهم الشخصية. فمع أنه كُتب بعناية فائقة وتدقيق من قِبله ومن قِبل زملائه في الفريق، إلا أنه يظل في النهاية "كود Ruby عشوائي يُشغّل على جهازك"، مؤكدًا كقاعدة عامة على ضرورة فحص وتفحص أي كود برمجي يُعرض على الشاشات في المؤتمرات التقنية قبل تنفيذه محليًا.

```mermaid flowchart TD accTitle: مسار تشغيل وتجربة قالب Rails المخصص لـ Ractor accDescr: يوضح الرسم البياني خطوات تشغيل القالب المخصص من الرابط وحتى خدمة الطلبات عبر Ractor.

subgraph Preparation ["إعداد التطبيق"] A["مسح رمز QR والحصول على الرابط"] --> B["مراجعة وفحص كود السكربت"] B --> C["تخطي Solid Gems وتفعيل دعم Ractor"] end

subgraph Execution ["التشغيل والمعالجة"] C --> D["تشغيل خادم الويب"] D --> E["إرسال طلبات ويب فعلية"] E --> F["معالجة وخدمة الطلب عبر Ractor الرئيسي"] end ```

[29:43](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=1783s) خارطة الطريق المستقبلية ودعوة مجتمع Ruby للمساهمة

ينتقل أندرو بعد ذلك للحديث عن المرحلة القادمة وما ينتظر هذا المشروع من عمل وتطوير؛ فالهدف المستمر داخل شركة Shopify خلال العام المقبل هو مواصلة توسيع دعم Ractor في إطار عمل Rails، والعمل على جعل المنظومة البيئية المحيطة برمتها أكثر توافقًا وأمانًا، بدءًا من مكتبات Ruby الخارجية (Gems) وصولاً إلى التطبيقات الحقيقية الإنتاجية. ومع أن فريق البنية التحتية في Shopify سيقود جزءًا كبيرًا من هذا العمل، إلا أن أندرو ركّز بحماس على أن الفرصة مفتوحة ومتاحة بالكامل أمام أفراد مجتمع Ruby للمشاركة الفعالة في هذه الرحلة.

ودعا الحضور والمطورين إلى اتخاذ خطوات عملية بسيطة: إنشاء تطبيق جديد بالاعتماد على القالب المتاح، ثم إضافة وظائف وميزات برمجية جديدة إليه. وبطبيعة الحال، من المرجح جدًا أن يصطدم المطور بخطأ متعلق بعزل Ractor (Ractor isolation error) في مكان ما، وهنا تكمن الفرصة الذهبية لتجهيز المساهمة القادمة وتصحيحها في كود Rails المصدري. كما شجع أصحاب المكتبات البرمجية أو المساهمين فيها على تدقيق حزمهم لجعلها Ractor-safe، وحث أصحاب المشاريع الجانبية على استكشاف مدى أمان تطبيقاتهم الصغيرة مع Ractor. وبيّن أن الاستعانة بالبرامج والوكلاء الآليين أثبتت جدارتها في رصد هذه المشكلات وعزلها وحلها بسرعة، مما يتيح للجميع إحراز تقدم لافت.

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

- **خطوات عملية للمجتمع:** - توليد تطبيق تجريبي عبر القالب البرمجي وإضافة مزايا جديدة لرصد أخطاء العزل وتقديم إصلاحات لـ Rails. - فحص حزم الـ Gems وتحديثها لتتوافق مع معايير الأمان الخاصة بـ Ractor. - تجربة تحويل المشاريع الجانبية واستخدام أدوات الأتمتة البرمجية لاكتشاف الثغرات وتصحيحها على نحو سريع. - التطلع إلى مشاركة تجارب واقعية لاستخدام Ractor داخل بيئات الإنتاج في المؤتمر القادم.

## Notable quotes > [00:10](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=10s) أرجو منكم الترحيب بي وتمنياتي لي بالتوفيق — Andrew Novoselac

> [04:06](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=246s) لا أعلم إن كنتم تتابعون الأخبار، لكن تكلفة الذاكرة أصبحت باهظة جدًا هذه الأيام — Andrew Novoselac

> [04:06](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=246s) أن خادم الويب القائم على Ractor يمكن أن يسمح لنا بزيادة التزامن في نظامنا دون زيادة الذاكرة أو زمن الاستجابة — Andrew Novoselac

> [09:22](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=562s) خطأ: لا يمكن مشاركة الإجراء self من ملف rails/initializable.rb في السطر 44 — Andrew Novoselac

> [09:22](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=562s) رأى بعض الأمور الغريبة في تطبيقات Rails، لكن نأمل ألا نُنشئ مُهيئات أثناء معالجة الطلبات — Andrew Novoselac

> [09:22](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=562s) undefined method freeze for Concurrent::Map — Andrew Novoselac

> [13:53](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=833s) لا يهتمون إلا بالمال ولا يتعبون أبدًا — Andrew Novoselac

> [19:42](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=1182s) حلقة وكيل أخرى فقط، يا صديقي — Andrew Novoselac

> [19:42](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=1182s) يغرقون في تعليمات الذكاء الاصطناعي البرمجية — Andrew Novoselac

> [28:15](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=1695s) لذا لا تعتاد عليه — Andrew Novoselac

> [29:00](https://www.youtube.com/watch?v=MVKUx-B_wHs&t=1740s) كود Ruby عشوائي يُشغّل على جهازك — Andrew Novoselac

## Mentioned Andrew Novoselac, Shopify, Ruby on Rails, Rails World 2026, Ractors, Threads, Processes, GVL (Global VM Lock), Writebook, Basecamp, Keno, Puma, Aaron Patterson, Concurrent::Map, Solid Cache, Active Record, Action Cable, David Hamilton, Rack, Claude 3 Opus, Toronto Ractors, Action View, Action Pack, RuboCop, ractor-dispatch, Nokogiri, Cougar, Kino

## Video description Ractors let Ruby run code truly in parallel inside a single process. They combine the parallelism of processes with the shared memory of threads. So what would it take to run Rails on a Ractor-based web server? At Rails World 2026, Andrew Novoselac, a developer on Shopify's Ruby on Rails Infrastructure team, takes a look at the effort to make Rails Ractor-safe.

Andrew starts by explaining how Ractors compare to processes and threads, and why a Ractor web server is worth pursuing. He then explains why making a framework the size of Rails Ractor-safe is hard, and how his team used an AI agent loop to map the problem. He closes with the work being upstreamed to Rails today and what's coming next.

***

Thank you Shopify for sponsoring the editing and post-production of these videos. Check out insights from the Engineering team at: https://shopify.engineering/

#RailsWorld #RubyOnRails #Ruby #Ractors #Concurrency #Performance

[Source](https://www.youtube.com/watch?v=MVKUx-B_wHs)

中文简报

Shopify借助AI智能体降低Rails服务器内存占用 通过Ractor运行Rails可将内存消耗降低7倍,但对象冻结以及数据库操作依赖主Ractor导致延迟暂时增加25%。 Andrew Novoselac阐述了Ruby中进程、线程与Ractor在并发机制上的本质差异,说明了基于Ractor的Web服务器如何在大幅节省内存的同时实现真正的并行。他指出了使Rails这一庞大框架实现Ractor安全所面临的严峻工程障碍,包括对象的深度冻结限制以及无法通过手动并行解决的连锁错误。为应对这一复杂难题,团队借助AI智能体循环(AI agent loop)进行测试并生成代码路径,覆盖了Rails近67%的代码,并绘制出全面的探索路线图。最后,他介绍了已合并至框架核心的修改、每夜隔离检查模式以及数据库访问方面尚未解决的挑战,同时向Ruby社区发出共同实现该目标的公开邀请。 由于每个Ractor拥有独立的GVL锁并共享内存,Ractor支持在单一进程内真正并行执行Ruby代码,兼具了进程与线程的优势。 (1:12) Shopify在实验性Ractor服务器Keno与Puma的对比测试中显示,Puma消耗的内存约为后者的7倍,但由于I/O任务受限于主Ractor,Keno的响应延迟增加了25%。 (4:06) Shopify团队使用耗资约2,000美元Claude 3 Opus额度的AI智能体循环,仅用两周时间就探索并覆盖了Rails代码库的67%,确保了169条代码路径的安全。 (15:32) 团队向Rails贡献了100多个Pull Request,借助在不中断服务器运行情况下记录内存违规的“隔离检查”(isolation check)模式来解决常量和类状态问题。 (20:33)

Reading summary

يعرض أندرو نوفوسيلاك مساعي فريق البنية التحتية في Shopify لجعل إطار عمل Ruby on Rails متوافقاً وآمناً مع نموذج التزامن Ractors لخفض استهلاك الذاكرة دون التضحية بالتوازي، مستعرضاً كيفية استكشاف نطاق المشكلة عبر وكيل ذكاء اصطناعي وأتمتة تصحيح أخطاء العزل. دوافع الاعتماد على Ractors ومكاسب الذاكرة (1:12) تتيح وحدات Ractor في لغة Ruby تنفيذاً برمجياً متوازياً حقيقياً داخل عملية نظام واحدة، متفوقة على الخيوط التقليدية المحكومة بقفل الآلة الافتراضية العام (GVL)، وممتازة مقارنة بالعمليات المستقلة التي تعزل الذاكرة بالكامل وتستهلك موارد باهظة التكلفة. أظهرت تجربة عملية أجراها الفريق لمقارنة أداء تطبيق Writebook بين خادم Keno القائم على 9 وحدات Ractor وخادم Puma المعتمد على 9 عمليات، انخفاض استهلاك الذاكرة في خادم Ractor بمقدار 7 أضعاف تقريباً. تحدي التجميد العميق وسلسلة أخطاء العزل (7:27) يشترط نموذج روبي لتشغيل وحدات Ractor تجميداً عميقاً وشاملاً لكافة الكائنات ومتغيرات الحالة المشتركة عبر الدالة `Ractor.make_shareable`، مما جعل التطبيق المباشر على Rails يواجه انهيارات فورية متسلسلة. عند اختبار استدعاء الدالة على كائن التطبيق، ظهرت مشاكل ارتباط الإجراءات البرمجية (Procs) بالمهيئات في `rails/initializable.rb`، تلاها عدم قابلية كائنات `Concurrent::Map` في جوهرة `Solid Cache` للتجميد لافتقارها للسياق الهرمي، فضلاً عن تعارضات في حزم أخرى مثل `Action Cable`. رسم خارطة الطريق البرمجية عبر وكيل الذكاء الاصطناعي (13:53) نظراً لتعذر المعالجة البشرية اليدوية لسلسلة الأخطاء المتتابعة واستنزافها للتركيز، أنشأ الفريق بيئة مستودع موحد (Repo Harness) تجمع روبي وRack وRails وتطبيقاً تجريبياً، وكلّف وكيل ذكاء اصطناعي بحلقة تكرار آلية لمعالجة الطلبات واكتشاف أخطاء العزل وإصلاحها تلقائياً. أسفرت العملية، بتكلفة حوسبة بلغت 2,000 دولار عبر نموذج Claude 3 Opus وأسبوع من الإشراف الهندسي، عن تغطية 67% من كود Rails وتشغيل 169 مساراً، مع إنتاج 200 تعديل قسّمها الفريق بشرياً إلى تعديلات نظيفة بنسبة 50%، وحلول واعدة بنسبة 40%، وتحديات تصميمية بنسبة 10%. ابتكار فحص العزل وتدفق التعديلات على النواة (20:33) لتجنب الإرهاق الإدراكي الناتج عن توليد الكود الآلي، اعتمد الفريق أسلوباً حتمياً عبر ابتكار راكتور "فحص العزل" (isolation check)، الذي يُصدر تحذيرات عند حدوث انتهاكات العزل دون إيقاف التنفيذ، ورُبط ذلك ببناء تجريبي ليلي يفحص 200 مسار لتحديد مواضع الخلل بدقة. أثمر هذا المسار عن تقديم أكثر من 100 طلب سحب إلى كود Rails المصدري، تضمنت تجميد الثوابت لخفض نحو 30% من الأخطاء، وتطبيق نمط تحديث النسخة المقروءة (Copy-on-Write) لحماية سمات الفئات في Active Record. معضلة قواعد البيانات وزمن الاستجابة (24:25) تعد عمليات الإدخال والإخراج ومجمعات الاتصال غير آمنة لـ Ractors بطبيعتها، ولذا لجأ الفريق مؤقتاً إلى جوهرة `ractor-dispatch` لتنفيذ بناء استعلامات SQL ومعالجة الطلبات داخل راكتور الطلب مع تمرير تنفيذ الاتصال الفعلي للراكتور الرئيسي. أدى هذا التصميم إلى زيادة زمن الاستجابة (latency) بنسبة 25% في تجربة Keno مقارنة بـ Puma، نتيجة تحول الراكتور الرئيسي إلى عنق زجاجة أحادي الخيط يخدم استعلاماً واحداً في الوقت ذاته، إضافة لتكلفة الاتصال الداخلي بين المفاعلات. طرح الفريق واجهة تجريبية بعنوان `Rails.application.reactorize` وقوالب مخصصة لتشغيل خوادم مثل Cougar وKeno محلياً مع استثناء Solid Gems مرحلياً، مؤكداً أن الهدف المستقبلي يتطلب إعادة هيكلة معمارية لنقل اتصالات قواعد البيانات بالكامل إلى راكتورات الطلبات وتأهيل المنظومة المحيطة بها لبيئات الإنتاج.

Source quotes

[0:10] Andrew Novoselac: أرجو منكم الترحيب بي وتمنياتي لي بالتوفيق [4:06] Andrew Novoselac: لا أعلم إن كنتم تتابعون الأخبار، لكن تكلفة الذاكرة أصبحت باهظة جدًا هذه الأيام [4:06] Andrew Novoselac: أن خادم الويب القائم على Ractor يمكن أن يسمح لنا بزيادة التزامن في نظامنا دون زيادة الذاكرة أو زمن الاستجابة [9:22] Andrew Novoselac: خطأ: لا يمكن مشاركة الإجراء self من ملف rails/initializable.rb في السطر 44 [9:22] Andrew Novoselac: رأى بعض الأمور الغريبة في تطبيقات Rails، لكن نأمل ألا نُنشئ مُهيئات أثناء معالجة الطلبات [9:22] Andrew Novoselac: undefined method freeze for Concurrent::Map [13:53] Andrew Novoselac: لا يهتمون إلا بالمال ولا يتعبون أبدًا [19:42] Andrew Novoselac: حلقة وكيل أخرى فقط، يا صديقي [19:42] Andrew Novoselac: يغرقون في تعليمات الذكاء الاصطناعي البرمجية [28:15] Andrew Novoselac: لذا لا تعتاد عليه [29:00] Andrew Novoselac: كود Ruby عشوائي يُشغّل على جهازك

Original transcript

[0:10] مرحباً بالجميع. اسمي [0:12] أندرو. سأتحدث اليوم [0:14] عن راكتور، وريلز، [0:16] والروبوتات، وأتمتة [0:17] عملية ضمان سلامة [0:18] راكتور. نعم، هذه [0:20] محاضرة حول جعل ريلز [0:22] آمناً مع راكتور. [0:23] سأعرّفكم بنفسي [0:24] قليلاً. أنا مطور في [0:26] شركة شوبيفاي، ضمن [0:27] فريق البنية التحتية [0:28] لروبي أون ريلز. أعيش [0:30] في هاميلتون، [0:31] أونتاريو. أعمل في [0:32] مجال تطوير تطبيقات [0:33] ريلز منذ عام ٢٠١٨، [0:34] وهذه أول مرة أشارك [0:35] فيها كمتحدث في مؤتمر. [0:37] لذا، أرجو منكم [0:38] الترحيب بي وتمنياتي [0:40] لي بالتوفيق. حسناً، [0:42] كما ذكرت، هذه [0:43] المحاضرة تدور حول [0:44] سلامة راكتور في ريلز. [0:47] سنبدأ بالحديث عن فكرة [0:49] خادم ويب قائم على [0:50] راكتور، وسنحاول [0:51] توضيح دوافعنا للقيام [0:53] بهذا العمل. ثم سنتحدث [0:54] عن سبب كون هذا العمل [0:56] صعباً للغاية، وكيف [0:57] يبدو شكله. ثم سأتحدث [0:59] عن رسم خريطة للمشكلة [1:00] بمساعدة حلقة وكيل [1:01] الذكاء الاصطناعي. [1:03] وأخيرًا، سأتحدث عن [1:04] العمل الذي قمنا به [1:06] فعليًا لدمج هذه [1:07] الأمور في Rails، وأين [1:08] وصلنا اليوم، وما هو [1:10] قادم في المستقبل. [1:12] فلنبدأ. أولًا، سنتحدث [1:15] عن فكرة خادم ويب Ractor. [1:16] للقيام بذلك، علينا أن [1:18] نتحدث عن ماهية Ractors. [1:20] Ractors هي أدوات أساسية [1:21] للتزامن تُمكّن من [1:23] التنفيذ المتوازي [1:24] داخل عملية واحدة. [1:25] ماذا يعني هذا؟ يمكننا [1:27] مقارنة Ractors بأدوات [1:28] التزامن الأخرى [1:29] الموجودة في Ruby، مثل [1:31] العمليات والخيوط. [1:32] لدينا هذا المخطط [1:33] المفيد. لنبدأ [1:34] بالعمليات. تعمل جميع [1:36] برامج Ruby في عملية، [1:37] والعمليات متوازية [1:39] تمامًا. هذا يعني أنها [1:40] تستطيع تشغيل كود Ruby [1:41] في نفس الوقت. تخيل أنك [1:43] فتحت علامتي تبويب في [1:44] الطرفية، وفتحت وحدتي [1:45] تحكم Rails، وكتبت بعض [1:46] الأوامر، يمكن [1:47] لكليهما تشغيل Ruby [1:48] بالتوازي. ومع ذلك، [1:49] فهما لا يتشاركان [1:50] الذاكرة. العمليات [1:51] معزولة تمامًا. فهي [1:53] تُحمّل شيفرتها [1:53] الخاصة، ولها مساحة [1:54] كائناتها الخاصة، وما [1:56] إلى ذلك. من ناحية أخرى [1:57] ، لدينا الخيوط. لذا، [1:58] يمكن أن يكون هناك خيط [2:00] واحد أو عدة خيوط تعمل [2:01] داخل عملية واحدة، [2:02] لكنها لا تعمل [2:03] بالتوازي. خيط واحد [2:04] فقط لديه ما يُسمى [2:05] بقفل الذاكرة [2:05] الافتراضية العام في [2:06] كل مرة، وهو الوحيد [2:07] الذي يمكنه تشغيل [2:08] شيفرة روبي. أما بقية [2:09] الخيوط فتكون جميعها [2:11] مُعلقة ومنتظرة. مع [2:12] ذلك، تتشارك الخيوط [2:13] الذاكرة. لذا، لديها [2:15] إمكانية الوصول إلى [2:16] نفس الكائنات. يكفي [2:17] تحميل الشيفرة مرة [2:17] واحدة فقط، وستتمكن [2:18] جميع الخيوط من الوصول [2:19] إليها. هنا يأتي دور [2:21] الراكتورات. في الواقع [2:22] ، تتمتع الراكتورات [2:23] بهاتين الميزتين. لذا، [2:24] يمكن للراكتورات [2:25] تشغيل الشيفرة [2:26] بالتوازي. يمكن أن [2:27] يكون هناك العديد من [2:28] الراكتورات داخل [2:29] عملية واحدة، جميعها [2:30] تُشغّل شيفرة روبي في [2:31] نفس الوقت. لا يوجد قفل [2:32] ذاكرة افتراضية عام، [2:33] أو في الواقع، لديهم [2:34] قفل ذاكرة افتراضية [2:35] عام خاص بهم. وهم [2:36] يتشاركون الذاكرة. لذا [2:38] ، يمكن لكل راكتور [2:39] التواصل مع نفس [2:40] الشيفرة، ونفس [2:41] الكائنات، وما إلى ذلك [2:43] . لفهم كيف يبدو ذلك، [2:44] لنفترض أن لدينا [2:45] فيبوناتشي سريع مع [2:47] خيوط. إذا أنجزت [2:48] خوارزمية فيبوناتشي [2:48] السريعة هذه العملية [2:49] الحسابية في 100 مللي [2:50] ثانية، يمكنك الحكم [2:51] بنفسك على مدى سرعة [2:52] ذلك، ولكن لأغراض [2:53] التوضيح فقط، لنفترض [2:54] أننا نريد إجراء هذه [2:55] العملية الحسابية [2:56] ثلاث مرات. لذا، سنوزع [2:57] العملية على ثلاثة [2:58] خيوط. كما نرى في هذا [2:59] الرسم البياني، خلال [3:00] أول 100 مللي ثانية، [3:01] سيتولى خيط واحد تنفيذ [3:02] GVL، بينما ستكون [3:03] الخيوط الأخرى متوقفة. [3:04] ثم سيتولى الخيط [3:05] الثاني تنفيذ GVL، [3:06] بينما ستكون الخيوط [3:07] الأخرى متوقفة، [3:08] وأخيرًا سيتولى الخيط [3:09] الثالث تنفيذ GVL. لذا، [3:10] على الرغم من أننا [3:11] أجرينا العملية [3:11] الحسابية لمدة 100 مللي [3:13] ثانية على ثلاثة خيوط، [3:14] إلا أن البرنامج [3:15] سيستغرق 300 مللي ثانية [3:16] للتنفيذ لأن خيطًا [3:17] واحدًا فقط يمكنه [3:18] تنفيذ كود روبي في كل [3:19] مرة. ولكن، إذا [3:20] استخدمنا وحدات Ractor، [3:21] سيتغير كل شيء. كل وحدة [3:23] Ractor لها GVL خاص بها، [3:24] لذا يمكنها جميعًا [3:25] إجراء هذه العملية [3:26] الحسابية بالتوازي. [3:27] وبالتالي، فإن الكود [3:29] الذي يستغرق 100 مللي [3:30] ثانية والذي تم تنفيذه [3:31] ثلاث مرات على ثلاث [3:32] وحدات Ractor سيُنفذ في 100 [3:34] مللي ثانية فقط. إذن، [3:36] نبذة عن تاريخ Ractors: [3:37] كانت ميزة تجريبية منذ [3:39] إصدار Ruby 3.0 في عام 2020. [3:41] بفضل بعض زملائي في [3:42] Shopify وآخرين في مجتمع [3:44] المطورين، شهد Ruby 4.0 [3:46] تحسينات هائلة، وهناك [3:47] المزيد من التحسينات [3:49] قادمة لاحقًا هذا [3:50] العام في Ruby 4.1، ونعتقد [3:52] الآن أن Ractors جاهزة [3:54] للاستخدام الفعلي في [3:55] بيئات الإنتاج. لذا، [3:57] في Shopify، نستكشف [3:58] العديد من الطرق التي [3:59] يمكننا من خلالها [4:00] استخدام Ractors في بيئات [4:01] الإنتاج. إحدى هذه [4:03] الطرق هي تجربة خادم [4:04] ويب قائم على Ractors. [4:06] فكيف سيبدو ذلك؟ خادم [4:08] الويب التقليدي متعدد [4:09] الخيوط لديه عملية [4:10] واحدة مع العديد من [4:12] الخيوط، كل منها يخدم [4:13] الطلبات. وهذا يعني أن [4:14] كل خيط يتناوب على [4:15] تشغيل كود Ruby بينما [4:16] تكون الخيوط الأخرى في [4:18] حالة انتظار. ما يعنيه [4:19] هذا هو أنه إذا أردنا [4:20] خدمة المزيد من [4:21] الطلبات المتزامنة، [4:22] فنحن بحاجة إلى المزيد [4:23] من الخيوط، وبالتالي [4:24] سنزيد من زمن [4:25] الاستجابة في نظامنا [4:26] بسبب زيادة حالات [4:27] الانتظار مع زيادة عدد [4:28] الخيوط. إذن، الطريقة [4:29] التقليدية التي [4:30] اتبعناها في Shopify وفي [4:31] مجتمع المطورين لحل [4:32] هذه المشكلة هي [4:33] استخدام خادم ويب [4:34] متفرع. عفوًا. خادم [4:36] الويب المتفرع يُشغّل [4:38] عملية واحدة ثم يُنشئ [4:40] عدة عمليات إضافية. [4:41] وهكذا، بدلًا من وجود [4:42] خيط واحد يستجيب للطلب [4:44] ، لدينا عملية واحدة [4:45] تستجيب للطلب. ويمكنها [4:47] جميعًا الاستجابة [4:48] للطلبات بالتوازي. مع [4:49] ذلك، لكل عملية [4:50] ذاكرتها الخاصة. أضع [4:51] علامة النجمة هنا [4:52] لوجود ما يُسمى "النسخ [4:53] عند الكتابة". على [4:54] مستوى نظام التشغيل، [4:55] قد تتشارك العمليات في [4:56] الذاكرة، ولكن كلما [4:57] طالت مدة تشغيلها، [4:58] سيتباعد مسارها. [4:59] ستُصبح صفحات الذاكرة [5:00] هذه غير صالحة. إنها [5:01] معزولة تمامًا. وهذا [5:03] يعني أنه إذا أردنا [5:04] المزيد من الطلبات [5:05] المتزامنة، فنحن [5:06] بحاجة إلى المزيد من [5:07] العمليات، وهذا يعني [5:08] أننا سنستخدم المزيد [5:09] من الذاكرة في نظامنا. [5:10] وأود التأكيد على هذه [5:12] النقطة. هذه هي [5:13] المشكلة التي نسعى [5:15] لحلها في Shopify. اليوم، [5:17] إذا أردنا المزيد من [5:18] التزامن، فإننا [5:19] نستخدم المزيد من [5:20] الذاكرة. لا أعلم إن [5:22] كنتم تتابعون الأخبار [5:23] ، لكن تكلفة الذاكرة [5:24] أصبحت باهظة جدًا هذه [5:26] الأيام. لذا، من المهم [5:27] جدًا لنا في Shopify، [5:28] وربما لكم أيضًا، أن [5:30] نحاول استخدام [5:31] أجهزتكم بكفاءة. عفوًا [5:33] ، حسنًا، يمكننا إعادة [5:34] النظر. تكلفة الذاكرة [5:37] باهظة جدًا اليوم. لذا [5:39] ، من المهم جدًا لنا في [5:40] Shopify، وربما لكم أيضًا [5:41] ، أن نستخدم الأجهزة [5:42] التي ندفع فيها مبالغ [5:44] طائلة بأكبر قدر ممكن [5:45] من الكفاءة. نريد [5:46] تلبية أكبر عدد ممكن [5:47] من الطلبات باستخدام [5:48] أقل قدر ممكن من [5:49] الذاكرة. ونعتقد أن [5:51] تقنية Raptor قد تساعدنا [5:52] في ذلك. إذًا، سيكون [5:53] خادم الويب القائم على [5:54] Raptor عبارة عن عملية [5:55] واحدة مع العديد من [5:56] وحدات Raptor التي تعالج [5:58] الطلبات بالتوازي. لكن [5:59] وحدات Raptor ستتشارك [6:00] الذاكرة. لذلك، كانت [6:02] لدينا هذه النظرية: أن [6:03] خادم الويب القائم على [6:05] Raptor يمكن أن يسمح لنا [6:06] بزيادة التزامن في [6:07] نظامنا دون زيادة [6:08] الذاكرة أو زمن [6:09] الاستجابة. وهذا ما [6:11] نطمح إليه. لاختبار [6:12] ذلك، استخدمنا تطبيق [6:14] كتابة الدفاتر مفتوح [6:15] المصدر من Basecamp. [6:16] باستخدام بعض [6:17] التقنيات التي سأتحدث [6:19] عنها لاحقًا، جعلنا [6:20] جزءًا صغيرًا من هذا [6:21] التطبيق آمنًا لـ Raptor. [6:22] ربطناه بخادم ويب قائم [6:24] على Raptor لاختبار أدائه [6:25] مقارنةً بـ Puma. وكانت [6:27] النتائج مذهلة. ما يجب [6:29] التركيز عليه هنا هو [6:31] الخلاصة. عند مقارنة [6:33] مجموعة معالجة مركزية [6:34] بتسعة عمليات مع Keno، [6:36] وهو خادم الويب [6:37] التجريبي الذي [6:38] استخدمناه بعملية [6:39] واحدة وتسعة معالجات [6:41] Raptor، لاحظنا زيادة في [6:42] الذاكرة بمقدار سبعة [6:44] أضعاف تقريبًا. هذا [6:45] أمرٌ مُغرٍ للغاية. [6:46] ماذا عن زمن الاستجابة [6:48] ؟ في الواقع، هناك [6:49] زيادة بنسبة 25%في زمن [6:51] الاستجابة عند [6:52] استخدام معالجات Raptor. [6:54] سأشرح السبب لاحقًا. [6:56] بمجرد فهم بعض [6:57] التقنيات التي [6:57] استخدمناها لتحقيق [6:58] ذلك، سيتضح سبب زيادة [6:59] زمن الاستجابة عند [7:00] استخدام معالجات Raptor، [7:02] وما يمكننا فعله حيال [7:03] ذلك مستقبلًا. لكن، [7:04] سأترك الأمر الآن [7:05] كتمرين للمشاهد ليفكر [7:07] في سبب ذلك. هذا أمرٌ [7:09] مغرٍ للغاية. يمكننا [7:11] توفير كل هذه الذاكرة [7:13] باستخدام رابتور فقط. [7:14] الآن، إذا كنت مطورًا [7:16] متشككًا مثلي، فربما [7:18] تفكر...عفوًا، قبل أن [7:20] أبدأ...هناك مقالٌ [7:21] كتبناه. يمكنك الاطلاع [7:23] عليه. يحتوي على جميع [7:25] التفاصيل حول هذه [7:26] التجربة. لنعد الآن [7:27] إلى الشكوك التي ربما [7:29] تراودك. وربما تفكر: " [7:31] ما المشكلة؟ كيف يمكن [7:32] أن يكون هذا صحيحًا؟ [7:33] ما الذي يجعل هذا [7:35] صعبًا؟" حسنًا، لنتحدث [7:37] عن ذلك. لماذا يصعب جعل [7:39] Rails آمنًا مع رابتور؟ [7:40] لقد أغفلتُ النقطة [7:41] الأساسية هنا. كنت [7:42] أستخدم مصطلح "آمن مع [7:44] رابتور"، لكنني لم [7:45] أُعرّفه بعد. لنتحدث [7:46] عن ماهيته. صحيح أن [7:48] وحدات Ractor تتشارك [7:49] الذاكرة، لكن هناك [7:51] قيدًا أقوى من ذلك. أي [7:53] كائن مشترك بين وحدات [7:54] Ractor يجب أن يكون [7:55] مُجمّدًا تجميدًا [7:57] عميقًا. ماذا يعني هذا [7:58] ؟ يعني أنه إذا كنتُ [8:00] كائنًا في لغة Ruby، لكي [8:01] أكون مُجمّدًا [8:02] تجميدًا عميقًا، لا [8:03] يكفي تجميدي أنا فقط، [8:04] بل يجب تجميد جميع [8:05] متغيرات مثيلاتي، [8:07] ومتغيرات مثيلات [8:08] الكائنات الأخرى، [8:09] وهكذا دواليك، وصولًا [8:10] إلى أسفل شجرة الكائن. [8:12] هذا هو معنى "أمان Ractor". [8:14] لنأخذ مثالًا: لنفترض [8:15] أن لدينا تطبيقًا [8:16] يحتوي على ملف تهيئة [8:17] عبارة عن جدول تجزئة ( [8:18] hash). إذا فتحنا أو [8:19] أنشأنا وحدة Ractor جديدة [8:20] ، وحاولنا الوصول إلى [8:22] جدول التجزئة هذا، [8:22] فسنحصل على خطأ في عزل [8:24] Ractor لأن جدول التجزئة [8:25] قابل للتغيير. لذا، لا [8:26] يمكننا الوصول إليه من [8:27] وحدة Ractor التي أُنشئت [8:28] عليها، والتي نسميها [8:30] في هذه الحالة "وحدة [8:31] Ractor الرئيسية". لتجاوز [8:33] هذه المشكلة، علينا [8:35] تجميد جدول التجزئة. [8:36] الآن، يمكننا الوصول [8:38] إليه من وحدة Ractor [8:39] الرئيسية. لكن، يجب [8:40] تجميد العناصر بشكل [8:42] كامل. لذا، إذا كان ملف [8:43] التكوين الخاص بنا [8:44] يحتوي على قيمة قابلة [8:45] للتغيير، مثل هذه [8:46] المصفوفة التي تحتوي [8:47] على "bar"، فلا يكفي [8:48] تجميد التجزئة فقط. [8:49] إذا فعلنا ذلك وحاولنا [8:50] الوصول إليها من خلال [8:51] Ractor الرئيسي، فسنحصل [8:52] على هذا الخطأ مرة [8:53] أخرى لأن المصفوفة [8:54] داخل التجزئة لا تزال [8:55] قابلة للتغيير. لذلك، [8:57] علينا تجميد كل من [8:58] المصفوفة داخل [8:59] التجزئة والتجزئة [9:01] نفسها. توفر لغة Ruby [9:02] أداة مفيدة للقيام [9:04] بذلك تُسمى [9:05] Ractor.make_shareable. إذا كنت [9:06] ترغب في معرفة المزيد [9:07] عن أساسيات استخدام [9:08] Ractors، وكيفية جعل [9:09] العناصر قابلة [9:10] للمشاركة، وما إلى ذلك [9:11] ، فقد تحدث آرون عن ذلك [9:12] بالتفصيل في كلمته [9:13] الرئيسية العام [9:13] الماضي. لذا، أنصحك [9:14] بشدة بمشاهدة ذلك [9:16] الجزء. أقصد، شاهد [9:17] الكلمة الرئيسية [9:17] كاملةً إذا لم تكن قد [9:18] شاهدتها، ولكن شاهد [9:19] ذلك الجزء تحديدًا [9:20] لمعرفة المزيد عن كل [9:21] ما يتعلق بإمكانية [9:22] المشاركة. إذن، ما [9:23] معنى هذا بالنسبة لـ [9:25] Rails؟ كيف نجعل Rails Ractor [9:28] آمنًا؟ أو ما يعنيه [9:30] جعل Rails Ractor آمنًا يعني [9:31] أننا نريد تشغيل [9:33] التطبيق، ثم استدعاء [9:34] الدالة ` make_shareable` في [9:36] تطبيق Rails الخاص بنا. [9:37] هذه هي الدالة التي [9:39] نستخدمها فعليًا [9:40] للاستجابة للطلبات. [9:41] بعد ذلك، في مُفاعل [9:42] جديد، نريد استدعاء [9:44] تطبيق Rails وتزويده [9:45] ببعض معلومات الطلب. [9:47] هذا هو الهدف. ما مدى [9:50] صعوبة ذلك؟ لذا، بدلًا [9:52] من محاولة شرح سبب [9:53] صعوبته، فكرتُ، لماذا [9:54] لا نستعرض ما سيحدث [9:55] إذا قمنا بذلك فعليًا؟ [9:56] لن أقوم بعرض توضيحي [9:57] مباشر. لقد نصحني [9:58] الكثيرون بشدة بعدم [9:59] القيام بذلك، لكن [9:59] دعونا نتخيل أنني أقوم [10:01] بعرض توضيحي مباشر. [10:02] لقد أنشأتُ تطبيق Rails [10:03] جديدًا. أقول لنفسي: " [10:04] ها ها ها. سأفتح وحدة [10:05] التحكم، وسأستدعي [10:07] الدالة ` make_shareable` في [10:08] المُفاعل. ماذا سيحدث؟ [10:11] " سأحصل على هذا الخطأ. [10:12] خطأ: لا يمكن مشاركة [10:15] الإجراء ` self` من ملف ` [10:18] rails initializable` في السطر 44 [10:21] من ملف ` rb`. حسنًا، [10:23] دعونا نلقي نظرة. ما [10:24] هذا؟ تطبيقات Rails [10:25] ومحركات Rails تُعرّف [10:26] مُهيئات. جميعها [10:26] تُخزّن في هذه [10:27] المجموعة. كما ترون، [10:28] لدينا بعض جداول [10:29] التجزئة، وهذه [10:30] الجداول تحتوي على [10:30] إجراءات، فعندما نطلب [10:31] من جدول التجزئة [10:32] مفتاحًا غير معروف [10:33] لديه، يُعيّن قيمة [10:34] فارغة لهذا المفتاح. [10:35] حسنًا، ماذا نفعل إذًا [10:36] ؟ الخطأ يتعلق [10:37] بالإجراء نفسه. لكي [10:38] يكون هذا الإجراء [10:39] آمنًا في بيئة Reactor، [10:40] يجب أن يكون الشيء [10:41] الذي يُشير إليه آمنًا [10:43] أيضًا. هذه هي المشكلة. [10:45] لكن إذا فكرنا في [10:46] الأمر، يُمكننا تجاوز [10:47] هذه المشكلة. بمجرد [10:49] تشغيل تطبيق Rails، نكون [10:50] قد حمّلنا جميع [10:52] المُهيئات وشغّلناها. [10:53] لن نضيف مُهيئات جديدة [10:55] أثناء الطلب، على [10:56] الأقل آمل ذلك. يعني، [10:57] لقد رأيتُ بعض الأمور [10:58] الغريبة في تطبيقات [10:59] Rails، لكن نأمل ألا [11:00] نُنشئ مُهيئات جديدة [11:01] أثناء الطلبات. لذا، [11:03] لسنا مضطرين للقلق [11:04] كثيرًا بشأن جعل هذا [11:05] المفاعل آمنًا. سنُسقط [11:06] الإجراء الافتراضي، [11:07] ونُجمّد كل هذه [11:08] الأشياء، وننتهي. [11:09] حسنًا، تجاوزنا [11:10] المشكلة الأولى. [11:11] لنُجرّبها مرة أخرى. [11:13] المفاعل يجعل تطبيق [11:14] Rails قابلاً للمشاركة. [11:16] الآن، نحصل على هذا [11:17] الخطأ: تجميد طريقة [11:18] غير مُعرّفة للخريطة [11:19] المتزامنة. إذًا، [11:20] الخرائط المتزامنة [11:21] غير قابلة للتجميد، [11:21] وبالتالي فهي غير آمنة [11:23] في المفاعل. والآن، [11:24] إذا كنتَ تنظر إلى [11:24] رسالة الخطأ هذه، [11:25] فربما تُفكّر: "من أين [11:26] تأتي هذه الخريطة [11:27] الحالية؟ ما هو سطر [11:29] الكود الذي يُسبّب هذا [11:30] الخطأ؟" وأحد عيوب Ruby [11:32] 4.0 هو أن رسائل الخطأ [11:34] لبعض عناصر المفاعل لا [11:36] تزال غير مُرضية [11:37] تمامًا. لذا، قام [11:39] فريقي بفتح بعض [11:40] التصحيحات في Ruby [11:41] لتحسين الوضع. بعد [11:43] تطبيق هذه التصحيحات، [11:45] سنحصل على رسالة خطأ [11:47] كهذه. تُحدد هذه [11:48] الرسالة مكان وجود [11:49] الخريطة المتزامنة، [11:51] بالإضافة إلى متغيرات [11:53] الكائن التي توجد فيها [11:54] ، وهكذا وصولًا إلى [11:56] أعلى تسلسل الكائنات. [11:58] بالتالي، يمكننا تتبع [11:59] مصدر هذه الخريطة [12:01] المتزامنة. هذه هي [12:03] التصحيحات، ويمكنكم [12:05] الاطلاع عليها. نأمل [12:07] أن تُصدر ضمن Ruby 4.1. [12:10] بالعودة إلى الشريحة [12:12] السابقة، عذرًا، [12:13] دعوني أعود. مصدر هذه [12:14] الخريطة هو Solid Cache. [12:16] الأمر معقد لأن Solid Cache [12:17] ليس جزءًا من Rails، بل [12:18] هو مكتبة مستقلة (gem) [12:20] تعتمد على Active Record. كيف [12:21] نجعلها آمنة [12:22] للاستخدام مع Reactor دون [12:23] أن يكون Rails كذلك؟ [12:24] الأمر غير واضح تمامًا [12:26] . لذا، دعونا نتجاوز [12:27] هذه الخطوة مؤقتًا. [12:29] سنستدعي Reactor ونتأكد [12:30] من حصولنا على النتيجة [12:31] المطلوبة. حسنًا، ها [12:33] نحن نتلقى خطأً آخر. [12:34] هذه المرة من Action Cable. [12:36] لن أطيل الحديث، لكن [12:38] من الواضح أن الأمر [12:39] سيستغرق بعض الوقت. [12:40] لماذا هذا صعب؟ أولًا، [12:42] لا يمكن تنفيذه [12:44] بالتوازي. لا يظهر إلا [12:45] خطأ واحد في كل مرة، [12:47] وعليك حله أو إيجاد حل [12:49] بديل لمعرفة الخطأ [12:51] التالي. لهذا السبب، [12:52] لا يمكنك رؤية خط [12:54] النهاية. لا أستطيع [12:55] تحديد عدد الأخطاء، [12:56] سواءً كانت 10 أو 100 أو [12:58] 1000. ببساطة، لا أعرف. [12:59] إضافةً إلى ذلك، عليك [13:00] التبديل بين السياقات [13:02] باستمرار. كما رأيتم، [13:03] بدأنا بـ Rails، [13:04] وتحديدًا عملية بدء [13:05] تشغيل Rails، ثم انتقلنا [13:07] إلى Solid Cache، ثم Action Cable. [13:09] لذا، بالنسبة لمطور لا [13:10] يستطيع تنفيذ العمل [13:12] بالتوازي، سيضطر إلى [13:13] مراجعة إطار عمل Rails [13:15] بالكامل بترتيب [13:16] عشوائي. ناهيك عن أننا [13:17] لم نصل بعد إلى أي شيء [13:19] صعب حقًا. لذا، بمجرد [13:20] تجميد التطبيق، سنبدأ [13:22] بالاستجابة للطلب، [13:23] وحينها ستظهر المشاكل [13:25] الهندسية الشيقة. كيف [13:26] نصل إلى قاعدة [13:27] البيانات؟ كيف نعرض [13:28] الصفحات؟ كيف نسجل [13:30] البيانات؟ وماذا عن [13:31] ذاكرة التخزين المؤقت [13:33] ؟ في الواقع، قمنا [13:34] بهذا العمل يدويًا [13:35] لفترة في Shopify، أو كما [13:37] ذكر ديفيد هاميلتون في [13:38] حديثه، ما نسميه العصر [13:39] القديم للبرمجة؟ أنا [13:41] أسميه البرمجة [13:42] الكلاسيكية. لقد جربنا [13:44] البرمجة الكلاسيكية [13:45] يدويًا لمحاولة حل هذه [13:46] المشكلة، وكان التقدم [13:48] بطيئًا للغاية. وفي [13:49] النهاية، بدأنا نفكر: [13:51] لا بد من وجود طريقة [13:53] أفضل. وهنا بدأت وكلاء [13:55] الذكاء الاصطناعي [13:56] بالتحسن بشكل ملحوظ. [13:58] فبدأنا نفكر: ربما [13:59] يمكننا استخدام وكيل [14:01] ذكاء اصطناعي [14:01] لمساعدتنا في حل هذه [14:03] المشكلة. الآن، أعتقد [14:04] أن من مزايا الذكاء [14:06] الاصطناعي ووكلاء [14:07] الذكاء الاصطناعي [14:08] أنهم لا يهتمون إلا [14:10] بالمال ولا يتعبون [14:11] أبدًا. إذا استمريتُ [14:12] في تزويد هذا الجهاز [14:14] بالرموز، فربما على [14:15] عكسي، لن يحتاج إلى [14:16] استراحة غداء، ولن [14:17] يشعر بالملل أو يرغب [14:18] في فعل شيء آخر. سيستمر [14:20] في العمل على المشكلة، [14:21] ويمكنني تركه يعمل إلى [14:22] الأبد. هذه هي الفكرة. [14:24] إذن، كيف نُهيئ ذلك؟ [14:26] نسمي هذا تسخير [14:28] المستودع. إنه مستودع [14:29] واحد يحتوي على كل ما [14:31] يحتاجه الوكيل لحل [14:32] مشكلة أمان المفاعل. [14:34] يحتوي على تبعيات Ruby و [14:36] Rack و Rails، وبعض الأشياء [14:38] الأخرى اللازمة. ثم [14:39] لديه تطبيق وهمي [14:41] مُرتبط بهذه التبعيات. [14:44] لديه بعض مهارات [14:45] الوكيل. فهو يعرف كيف، [14:46] على سبيل المثال، [14:47] يُظهر رسالة "عذرًا، [14:49] جهاز النقر الخاص بي [14:50] لا يستجيب". يعرف كيف [14:51] يُجري الاختبارات، [14:52] ويعرف كيف يُعيد بناء [14:54] Ruby إذا أجرى تغييرات [14:55] عليه، ويمكنه بناء [14:56] نسخة تطوير جديدة [14:57] لنفسه، إلخ. والأهم من [14:59] ذلك، لديه الخطة. إذن، [15:02] ما هي الخطة؟ أخبرنا [15:04] الوكيل أننا نريد منه [15:06] التكرار حتى يتمكن من [15:07] إنشاء تطبيق Rails قابل [15:09] للمشاركة. ثم نريده أن [15:11] يستمر في التكرار حتى [15:13] يتمكن من عرض استجابة [15:14] 200 OK. ثم الجزء الأكثر [15:16] إثارة للاهتمام، وهو [15:17] البدء في إضافة وظائف [15:18] جديدة إلى تطبيقك لا [15:19] تعمل مع المفاعلات، ثم [15:20] إيجاد طريقة لجعلها [15:22] تعمل. واستمر في فعل [15:23] ذلك إلى ما لا نهاية [15:24] حتى نطلب منك التوقف. [15:25] هذا ما تركناه للوكيل، [15:27] بالإضافة إلى مجموعة [15:28] من التفاصيل حول كيفية [15:29] العمل مع المفاعلات، [15:30] بالطبع. إذن، ماذا فعل [15:32] ؟ لقد أنشأ لنا هذا [15:33] التقرير الرائع، في [15:34] الواقع. آسف، إنه ساطع [15:36] للغاية. ويقول التقرير [15:38] : "يحتوي تطبيقي الآن [15:39] على 169 مسارًا. جميعها [15:41] تعمل ضمن المفاعلات، [15:43] وهذا يغطي حوالي 67%من [15:44] قاعدة كود Rails." وكما [15:46] ترون، فهو مُقسّم حسب [15:47] منطقة قاعدة الكود. [15:48] لذا، نعم. هذه نتائج [15:50] رائعة حقًا. لقد كان [15:52] أداؤه جيدًا جدًا. بعض [15:54] الإحصائيات للمهتمين [15:55] بالتفاصيل التقنية. [15:56] هذا يعادل حوالي 2000 [15:57] دولار من رصيد Opus 47، [15:58] والذي كان أفضل نموذج [16:00] في ذلك الوقت. استغرق [16:01] الأمر حوالي أسبوع من [16:02] العمل البشري لتشغيله. [16:04] أجرينا بعض الحلقات [16:05] الإضافية لمحاولة [16:07] تحسين بعض الحلول، [16:08] وأيضًا كإجراء وقائي [16:10] للتأكد من أن ما فعله [16:11] مرةً، يمكنه فعله مرة [16:13] أخرى. حسنًا. هذا كل [16:15] شيء. هذا كل شيء يا [16:17] رفاق. هذا كل شيء [16:18] بالنسبة لي. لقد جعلنا [16:20] Ractor آمنًا في Rails قبل GT6 [16:22] . هذا هو شعار Toronto Ractors [16:30] الرائع الذي نسميه [16:32] الشعار غير الرسمي لـ [16:34] Ractors في Shopify. مهلًا. [16:39] أعلم أن هذا يتغير [16:41] بسرعة. تم هذا العمل [16:42] منذ 3 أو 4 أشهر. لكن [16:44] ربما تكون جزءًا من [16:45] نادي "ما زلت أقرأ [16:46] الكود"، وقد تتساءل: " [16:48] هل قرأت أيًا من هذا [16:49] الكود الذي أنشأه [16:50] البرنامج؟" نعم، قرأت [16:54] كل شيء. استغرق إعداد [16:56] النموذج أسبوعًا [16:57] واحدًا، ومراجعته [16:59] أسبوعين. احتوى [17:00] النموذج النهائي الذي [17:02] راجعته على حوالي 200 [17:03] تغيير في إطار عمل Rails، [17:05] معظمها في صميم الإطار [17:06] ، مثل Action View و Active Record [17:08] و Action Pack. حاولت تصنيف [17:10] التغييرات بناءً على [17:12] مدى صعوبتها، ومحاولة [17:14] رصد بعض المشكلات [17:15] والأنماط الشائعة [17:17] التي رصدها النظام. [17:19] وكانت النتائج [17:20] كالتالي: حوالي 50%من [17:22] التغييرات التي [17:23] أجراها النظام بسيطة، [17:25] وتبدو رائعة، وجاهزة [17:26] للدمج مباشرةً. 40%منها [17:28] كانت في الاتجاه [17:29] الصحيح تمامًا، لكنها [17:30] تحتاج فقط إلى بعض [17:31] الاهتمام البشري، إما [17:33] بتوجيه الذكاء [17:33] الاصطناعي أو بتنظيف [17:35] الكود، وبعدها يمكننا [17:36] دمجها. أما الـ 10% [17:37] المتبقية، فكانت [17:38] تتطلب جهدًا تصميميًا [17:40] مركزًا بالكامل، [17:41] بمشاركة البشر [17:42] والأنظمة لتحديد [17:43] كيفية تطبيقها في Rails. [17:45] أعتقد أن هذا مذهل [17:47] حقًا. حسنًا، لقد [17:48] جعلني هذا أفكر قليلًا [17:49] في عيوب وكلاء الذكاء [17:51] الاصطناعي، وهي أنهم [17:52] لا يهتمون إلا بالمال [17:54] ولا يتعبون أبدًا. لذا [17:56] ، لم يكن لدى الوكيل أي [17:57] تحفظات بشأن كتابة [17:58] دوال من 5000 سطر، أو [17:59] تكرار نفس النمط في [18:01] جميع أنحاء قاعدة [18:02] بيانات Rails، بدلًا من [18:03] محاولة إيجاد واجهة [18:04] برمجة تطبيقات (API) [18:05] مناسبة لشيء يهمنا [18:07] كثيرًا في Rails. كما أنه [18:08] كان على استعداد [18:09] لتنفيذ عمليات عزل [18:10] أخطاء المفاعل في بعض [18:11] المواضع لتجاوز [18:12] المشاكل. لذا، لم يكن [18:13] مثاليًا، لكننا لم نكن [18:15] نبحث عن كود مثالي. ما [18:17] يهمنا هو أن الوكيل [18:19] زودنا بخريطة. كانت [18:21] هذه في السابق مشكلة [18:23] معقدة للغاية، كنا [18:25] نعتقد أنها ستستغرق [18:26] منا عامًا كاملًا لفهم [18:29] كل ما نحتاجه لجعل Rails [18:30] آمنًا من حيث المفاعل. [18:32] ثم في غضون أسبوع أو [18:33] أسبوعين، أصبح لدينا [18:34] هذا النموذج الأولي [18:35] الضخم مع خريطة شاملة [18:37] لجزء كبير من العمل. [18:38] وهذا أمر مذهل حقًا. [18:40] حسنًا، دعونا نتحدث [18:41] عما فعلناه فعليًا [18:42] لدمج هذه الميزات في [18:44] النسخة الرئيسية. [18:45] لدينا الآن نموذج أولي [18:47] ضخم يقوم بالعديد من [18:48] المهام. لم أقرأ كل سطر [18:50] من أكواد التطبيق، لذا [18:52] لا أعرف كل ما يفعله. [18:53] بدأنا نفكر، يبدو أن [18:55] هذه المشكلة قابلة [18:56] للحل، ولكن ما الذي [18:58] سنبدأ به في Rails؟ ما [18:59] الذي سندمجه في النسخة [19:00] الرئيسية؟ استقررنا [19:02] على المرحلة الأولى [19:03] مما نسميه دعم المفاعل [19:04] التجريبي. وهو ببساطة [19:06] كالتالي: يمكنك [19:07] استخدام Rails new لإنشاء [19:09] تطبيق جديد. يمكنك [19:10] إنشاء مسارات هيكلية. [19:12] يمكنك جعل التطبيق [19:14] قابلاً للمشاركة. بعد [19:15] ذلك، لكل مسار، ستعمل [19:17] هذه المسارات كمفاعل. [19:19] هذا هو النطاق الذي [19:20] أردنا البدء به. إنه [19:21] نطاق جيد جدًا وقابل [19:22] للتحقيق وسهل الوصف، [19:24] ولكنه في الواقع يغطي [19:25] بعض الأمور المهمة [19:26] جدًا. أولًا، يغطي جعل [19:28] التطبيق قابلاً [19:29] للمشاركة. يغطي الوصول [19:30] إلى قاعدة البيانات، [19:32] والتسجيل، وعرض [19:33] الواجهة، أي جوهر أي [19:34] تطبيق ويب. حسنًا، في [19:35] الوقت نفسه، يسمح لنا [19:36] هذا بتجاوز بعض الأمور [19:38] المعقدة التي من [19:39] الأفضل لنا القيام بها [19:40] لاحقًا بعد أن نتقن [19:41] بعض أنماط أمان [19:42] المفاعل. لذا، في [19:43] الوقت الحالي، لم نقم [19:44] بتعديل Action Cable أو [19:45] المهام أو التبعيات [19:47] مثل Solid Cache. كما لم نقم [19:48] بتعديل وضع التطوير، [19:49] ويرجع ذلك أساسًا إلى [19:51] التحميل الكسول. الآن، [19:52] نحن جاهزون لبدء نشر [19:54] بعض التعليمات [19:55] البرمجية، لكننا [19:56] نواجه مشكلة. كيف نربط [19:57] هذا النموذج الأولي [19:58] الضخم والفوضوي [19:59] بنطاقنا الأصغر ونعرف [20:00] ما نحتاجه فعليًا [20:01] لنشره في المصدر [20:02] الرئيسي؟ لقد فكرت في [20:03] هذا الأمر كثيرًا. كان [20:05] لدينا ميلٌ ما للقول: " [20:06] حلقة وكيل أخرى فقط، [20:08] يا صديقي. دعنا نشغل [20:09] الذكاء الاصطناعي مرة [20:10] أخرى على النطاق [20:11] الجديد، ويمكنه [20:11] الرجوع إلى النموذج [20:12] الأولي القديم [20:13] وإخبارنا بالتغييرات [20:14] المرتبطة ببعضها." [20:15] لكنني بدأت أشعر بأننا [20:16] نغرق في تعليمات [20:18] الذكاء الاصطناعي [20:19] البرمجية، وأن كل حلقة [20:20] جديدة نقوم بتشغيلها [20:21] تُضيف عبئًا معرفيًا [20:23] إضافيًا لقراءة [20:24] التعليمات البرمجية [20:25] وفهم ما يتعلق بها. [20:26] حسنًا، أردنا شيئًا [20:28] أكثر ثباتًا، شيئًا [20:29] يمكننا تشغيله [20:30] والحصول على نتائج [20:32] محددة منه. ومن هنا [20:33] جاءت فكرة فحص العزل [20:35] في المفاعل. هذه طريقة [20:37] جديدة ابتكرناها، وهو [20:39] مفاعل خاص، لذا فهو لا [20:41] يمتلك خصائص التوازي [20:42] للمفاعلات الحقيقية، [20:44] لأنه بدلًا من إظهار [20:46] الأخطاء، يُصدر [20:47] تحذيرات. وهذا مفيد [20:48] جدًا، إذ يسمح لنا [20:50] بجمع جميع الأخطاء [20:51] التي قد تحدث أثناء [20:52] الطلب. إليكم كيف يبدو: [20:54] إذا كان لديّ الثابت foo [20:56] وحاولت إدخاله في [20:57] المفاعل، فسأحصل [20:58] فورًا على خطأ عزل، [21:00] وسيتوقف برنامجي، [21:01] تمامًا كما رأينا [21:02] عندما كنا نشرح كيفية [21:04] جعل Rails آمنًا [21:05] باستخدام المفاعل. [21:07] ولكن مع فحص العزل، [21:08] أحصل الآن على ثلاثة [21:09] تحذيرات، واحد لكل مرة [21:11] أصل فيها إلى foo، ثم [21:12] سيعمل برنامجي كما هو [21:14] مُفترض، ويطبع "Hello world" [21:15] . ممتاز! إذًا، هذا [21:18] مفيد جدًا. وهذا الأمر [21:19] مُتاح الآن في نظام [21:21] تتبع الأخطاء [21:21] والميزات الخاص بلغة [21:23] روبي. هناك نقاشٌ حول [21:24] أفضل طريقة لتنفيذه، [21:26] لكننا نأمل أن يكون [21:28] جزءًا من روبي 4.1. لذا، [21:30] قمنا بربطه بإصدار [21:31] تجريبي ليلي. يقوم هذا [21:33] الإصدار بسحب آخر [21:34] تحديث لـ Rails، وإنشاء [21:35] عملية، وإنشاء [21:36] المسارات، ثم تشغيل [21:37] جميع المسارات من خلال [21:39] عملية بناء. بدأنا [21:40] بحوالي 200 مسار فريد. [21:42] هذه لقطة شاشة من [21:43] الأسبوع الماضي بينما [21:44] كنا نستعد لإنهاء هذا [21:46] المشروع ومعالجة [21:47] الأخطاء الأخيرة. [21:48] إليكم كيف يبدو. [21:50] الأخطاء مُصنفة حسب [21:51] مكان حدوثها في قاعدة [21:52] التعليمات البرمجية، [21:54] وتتبع الأخطاء، وما [21:55] إلى ذلك. لذا، هذا [21:57] مفيدٌ للغاية. الآن، [21:58] لدينا كل ما نحتاجه [21:59] للبدء في العمل على [22:00] هذا المشروع. لدينا [22:01] النموذج الأولي [22:02] المكتوب بواسطة [22:02] الذكاء الاصطناعي [22:03] والذي يُظهر لنا بعض [22:04] الأنماط اللازمة لحل [22:05] مختلف المشاكل. نحن [22:06] نتابع هذه الأخطاء [22:07] مباشرةً كل يوم، فمع [22:08] كل تحديث يُضاف إلى Rails [22:10] ، نرى أحدث الأخطاء [22:11] التي قد تظهر ضمن [22:12] النطاق المطلوب. لدينا [22:14] كل ما نحتاجه، ثم بدأت [22:15] طلبات السحب تتدفق [22:17] بغزارة. خلال أشهر [22:18] الصيف، أرسل فريقي [22:19] أكثر من 100 طلب سحب إلى [22:21] Rails لتحسين أمان [22:22] المفاعلات. كما ذكرت [22:24] سابقًا، هناك مستويات [22:26] مختلفة من الجودة، [22:28] بدءًا من أبسطها [22:29] وصولًا إلى أصعبها، [22:31] وصولًا إلى أكثرها [22:32] تعقيدًا. لنلقِ نظرة [22:34] على مثال لكل منها. [22:35] المثال الأول: تجميد [22:37] الثوابت. يحتوي Rails على [22:39] العديد من الثوابت [22:40] التي تتضمن مصفوفات أو [22:41] جداول تجزئة قابلة [22:42] للتغيير. ليس هناك سبب [22:44] حقيقي لإمكانية [22:45] تغييرها، فهي تُعيّن [22:46] عند تحميل الكود ولا [22:48] تتغير أبدًا. لذا، إذا [22:49] حاولت الوصول إليها في [22:51] مفاعل آخر، فستحصل على [22:52] خطأ. أسهل حل هو [22:53] تجميدها. لقد طبقنا [22:55] هذا في جميع أنحاء [22:56] قاعدة بيانات Rails. يوجد [22:57] بالفعل RuboCop يقوم بهذا [22:58] نيابةً عنك. لذا، إذا [23:00] كنت تعمل على جعل أي [23:01] شيء آمنًا للاستخدام [23:02] مع Reactor، أنصحك بشدة أن [23:03] تبدأ بتفعيل هذا [23:04] الشرطي. أعتقد أن هذا [23:06] قلل حوالي 30%من [23:08] الأخطاء. حسنًا، [23:09] لننتقل إلى شيء أكثر [23:11] تعقيدًا. يحتوي Rails على [23:12] الكثير من حالة [23:13] التطبيق العامة [23:14] الموجودة في سمات [23:15] الفئات. تحتوي هذه [23:16] السمات على قيم قابلة [23:17] للتغيير، وإذا حاولت [23:18] الوصول إليها من Reactor [23:19] الرئيسي، فستحصل على [23:20] خطأ. لدينا هنا نماذج [23:21] Active Record تحتوي على [23:23] مصفوفة سمات للقراءة [23:24] فقط. الآن، هنا نختلف [23:26] قليلًا عما توصل إليه [23:27] الوكيل في البداية. [23:28] كان لدى الوكيل دالة [23:30] مكونة من 5000 سطر في Rails [23:31] ، والتي وجدت كل مكان [23:32] في التطبيق ضمن إطار [23:34] العمل يقوم بهذا، ثم [23:35] جمدتها جميعًا قبل [23:36] تجميد التطبيق. لم [23:37] نُفضل ذلك لعدة أسباب. [23:39] أولًا، يتطلب الأمر [23:40] الكثير من إدارة [23:41] السجلات، وثانيًا، [23:42] يُنشئ حالة يكون فيها [23:43] التطبيق آمنًا [23:44] للاستخدام مع Reactor أو [23:45] لا، وعلينا أن نتذكر [23:46] استدعاء هذه الدالة. [23:47] نريد تجنب ذلك قدر [23:48] الإمكان. لذا، توصلنا [23:50] إلى ما نسميه نمط [23:51] تحديث النسخة [23:52] المقروءة. لم نخترع [23:53] هذا المصطلح، لكننا [23:54] نسميه بهذا الاسم. [23:56] يعني هذا النمط أن [23:57] المصفوفات ستُجمّد [23:59] افتراضيًا. عند إضافة [24:00] عنصر جديد إلى [24:02] المصفوفة، نقوم بنسخه. [24:04] نضيف العناصر الجديدة [24:05] ثم نُجمّدها مرة أخرى [24:07] ونُعيد تعيينها. هذا [24:08] مفيد جدًا لأن جميع [24:09] هذه الأجزاء في إطار [24:10] العمل ستكون آمنة من [24:11] التداخل في أي مرحلة [24:13] من مراحل دورة حياة [24:14] البرنامج. إذا أردت [24:15] معرفة المزيد عن هذا [24:16] النمط والعديد من [24:17] الأنماط الأخرى، فقد [24:18] نشر زميلي هارلي [24:19] مقالًا على مدونته [24:20] الأسبوع الماضي يشرح [24:21] فيه العديد من الأنماط [24:22] المختلفة التي [24:23] استخدمناها في إطار [24:24] العمل. حسنًا، أخيرًا، [24:25] لننتقل إلى نمط معقد: [24:27] الوصول إلى قاعدة [24:28] البيانات. هذا النمط [24:29] معقد. عمليات الإدخال [24:31] والإخراج غير آمنة [24:32] بطبيعتها من التداخل، [24:33] إذ لا يمكنها تجاوز [24:34] حدود التداخل. [24:35] بالإضافة إلى ذلك، [24:36] تُعتبر مجموعات [24:37] الاتصالات قابلة [24:38] للتغيير بطبيعتها. [24:39] يتتبعون حالة مجموعة [24:40] من الاتصالات [24:41] المختلفة ويحتاجون [24:41] إلى معرفة الجهة [24:42] المؤجرة لها. لذا، ليس [24:43] من الواضح تمامًا كيف [24:45] نجعل مثل هذا المفاعل [24:46] آمنًا. ما توصلنا إليه [24:47] هو استخدام هذه الأداة [24:49] أو هذه الجوهرة [24:50] المسماة "Reactor Dispatch". [24:51] عذرًا، لقد نسيت رمز [24:52] الاستجابة السريعة، [24:53] لكن يمكنني إرسال [24:54] الرابط لاحقًا. نستخدم [24:55] هذه الجوهرة المسماة " [24:56] Reactor Dispatch" والتي تتيح [24:57] لنا تمرير العمل إلى [24:58] مفاعل آخر. إليك مثال: [25:00] نُنشئ مفاعلًا جديدًا [25:01] ، ونُجري بعض العمليات [25:02] التي تستهلك موارد [25:03] المعالج بكثافة، ثم [25:04] نحتاج إلى القيام بشيء [25:05] غير آمن للمفاعل. لذلك [25:06] ، نستدعي المفاعل [25:07] الرئيسي لتنفيذ الكود [25:08] غير الآمن. نحصل على [25:09] النتيجة، ثم نُجري [25:10] المزيد من العمليات [25:11] التي تستهلك موارد [25:12] المعالج بكثافة [25:13] باستخدامها. يمكننا [25:14] تقسيم هذا الكود حسب [25:15] المفاعل الذي يُنفذ [25:16] عليه، وسيبدو كالتالي: [25:17] نُنشئ المفاعل على [25:18] المفاعل الجديد أو على [25:19] المفاعل الرئيسي. على [25:20] المفاعل الجديد، [25:21] نُجري العمليات التي [25:22] تستهلك موارد المعالج [25:23] بكثافة. عدنا إلى [25:24] راكتور الرئيسي، إلخ. [25:26] هذا هو النمط الذي [25:27] نحاول استخدامه [25:28] للوصول إلى قاعدة [25:28] البيانات. نريد القيام [25:30] بكل ما في وسعنا على [25:31] راكتور خدمة الطلبات، [25:32] ولكن عندما نحتاج [25:33] فعليًا إلى التواصل مع [25:34] قاعدة البيانات [25:34] وإجراء عمليات [25:35] الإدخال والإخراج، [25:36] والحصول على الاتصال، [25:37] وما إلى ذلك، سنعود [25:38] إلى راكتور الرئيسي. [25:39] الآن، دعونا نلقي نظرة [25:41] على شكله. هذا شرح مبسط [25:43] للغاية، ولكن تخيل أن [25:45] لدينا طلب POST. في [25:47] راكتور الطلبات، نقوم [25:51] بتنفيذ البرامج [25:53] الوسيطة، ونستدعي [25:54] وحدة تحكم POST لعرض [25:56] البيانات. نبني [25:57] استعلام SQL، والآن نحن [25:59] جاهزون لتنفيذه. لذلك، [26:02] نتصل براكتور الرئيسي. [26:03] ننفذ استعلام SQL هناك. [26:05] الآن، نحصل على [26:06] النتيجة على راكتور [26:07] الطلبات. نُهيئ نموذج [26:09] POST، ثم نعرض بعض صفحات [26:11] HTML. ممتاز. الآن، [26:13] سيلاحظ المشاهد الفطن [26:14] أننا أضفنا للتو بعض [26:16] عمليات الحظر إلى [26:17] تطبيق الويب الخاص بنا [26:18] . أين يحدث ذلك؟ حسنًا، [26:20] لنفترض وجود طلبين، [26:22] كلاهما من نوع GET و POST. [26:23] يقوم كلا الطلبين [26:24] بتنفيذ برامجهما [26:25] الوسيطة. عفوًا، النقر [26:27] التلقائي. يصل كلا [26:29] الطلبين إلى مرحلة [26:30] تنفيذ استعلام SQL. [26:31] والآن عدنا إلى [26:32] المفاعل الرئيسي، لكن [26:33] المفاعل الرئيسي لا [26:34] يستطيع القيام إلا [26:35] بمهمة واحدة في كل مرة. [26:36] لذا، يقوم أولًا [26:37] بتنفيذ استعلام SQL [26:38] للطلب الأول. ثم يقوم [26:40] بتنفيذ استعلام SQL [26:41] للطلب الثاني، بينما [26:43] نحصل على النتيجة في [26:44] مفاعل الطلب الأول. ثم [26:46] نبدأ في تهيئة نموذج [26:48] POST. الآن نحصل على [26:49] النتيجة في مفاعل [26:50] الطلب الثاني. ثم نعرض [26:52] صفحة HTML الخاصة بنا. [26:54] لكن ما ستلاحظه هو أن [26:55] مفاعل الطلب الثاني [26:57] كان لديه بعض التأخير [26:58] مقارنةً بمفاعل الطلب [26:59] الأول. والآن يمكننا [27:01] الإجابة على السؤال: [27:02] لماذا أدى إدخال [27:03] المفاعلات إلى زيادة [27:05] التأخير؟ أحد الأسباب [27:06] هو أن الاتصال بقاعدة [27:08] البيانات وإرسال [27:09] البيانات إلى المفاعل [27:10] الرئيسي يُسبب بعض [27:12] التعطيل، وبالتالي [27:13] بعض التأخير. لذا، [27:14] يُعدّ إرسال المفاعل [27:16] أداةً مفيدةً للغاية، [27:17] لكن هدفنا على المدى [27:18] البعيد هو تنفيذ 100%من [27:19] التعليمات البرمجية [27:21] على مفاعل الطلبات. مع [27:22] ذلك، يُوفر لنا إرسال [27:24] المفاعل حلاً مؤقتاً [27:25] ريثما يتحقق ذلك. [27:26] أعتقد أننا نأمل على [27:27] المدى البعيد، فيما [27:28] يخص الوصول إلى قاعدة [27:29] البيانات، أن تُخزّن [27:30] الاتصالات على مفاعل [27:31] خاص بها، وأن يتمكن [27:32] مفاعل الطلبات من [27:33] التحقق من هذا الاتصال [27:34] والتحكم فيه، لكن هذا [27:35] عاملٌ مهمٌ في Rails، [27:36] ونأمل أن نصل إلى ذلك [27:37] يوماً ما. من الأمثلة [27:38] الأخرى الحالة [27:39] الكسولة، حيث يحتوي [27:40] Active Record على حالة [27:41] كسولة في النماذج، [27:42] تُعاد تهيئة البيانات [27:43] فقط عند الاتصال [27:44] بقاعدة البيانات لأول [27:45] مرة، ويجب ضبطها على [27:46] المفاعل الرئيسي. لا [27:47] يُمكننا ضبطها على [27:49] مفاعل الطلبات. كما لا [27:50] تزال هناك العديد من [27:51] المكتبات غير الآمنة [27:52] للاستخدام مع [27:52] المفاعلات، ومن [27:53] أبرزها Nokogiri. لذا، [27:54] علينا العودة إلى [27:55] المفاعل الرئيسي [27:56] لاستخدام Nokogiri في [27:56] الوقت الحالي. [27:57] بالإضافة إلى ذلك، فإن [27:58] التواصل بين [27:59] المفاعلات ليس [28:00] مجانيًا. لذا، علينا [28:01] توخي الحذر عند اختيار [28:03] استخدام التواصل بين [28:04] المفاعلات أثناء [28:05] الطلب. هذا طلب سحب [28:07] مثير للاهتمام حقًا. [28:08] لقد بسّطته كثيرًا، [28:10] لكنني أنصح بشدة [28:11] بقراءة الكود إذا كنت [28:12] ترغب في معرفة المزيد. [28:13] إنه عمل هندسي رائع [28:15] حقًا. حسنًا، كيف [28:17] يمكنك تجربته بنفسك؟ [28:19] لقد قدمنا طريقة جديدة [28:21] تُسمى "Rails application [28:23] reactorize". للأسف، هناك [28:24] بعض الإجراءات التي [28:26] يجب عليك اتباعها قبل [28:27] تجميد التطبيق، وكلها [28:29] مُضمنة في هذه الطريقة [28:30] . لذا، إذا استدعيتها، [28:32] فستتلقى تحذيرًا بأن [28:33] دعم المفاعلات في Rails [28:35] تجريبي وقابل للتغيير [28:36] ، حتى اسم الطريقة [28:37] قابل للتغيير، لذا لا [28:39] تعتاد عليه. بعد ذلك، [28:40] سيصبح تطبيقك قابلاً [28:42] للمشاركة. هناك بعض [28:43] خوادم الويب القائمة [28:44] على المفاعلات التي [28:46] يمكنك الاطلاع عليها. [28:47] Cougar خفيف جدًا وبسيط [28:48] للغاية. يمكنك على [28:50] الأرجح قراءة الكود [28:51] بالكامل بسرعة. Kino [28:52] أكثر ثراءً بالميزات، [28:54] وهو مثير للاهتمام [28:55] حقًا. إذن، ألقِ نظرة [28:56] على كليهما. ثم أنشأنا [28:58] قالبًا يُتيح لك إنشاء [29:00] تطبيق Rails مُهيأ [29:01] تمامًا لاستخدام Ractor، [29:03] مثل تخطي Solid Gems، [29:04] وتفعيل بعض الميزات [29:06] الأخرى اللازمة [29:07] لتشغيل دعم Ractor. يمكنك [29:09] تشغيل هذا البرنامج [29:10] النصي، اتبع رمز [29:11] الاستجابة السريعة (QR [29:12] code) للحصول عليه. يحتوي [29:13] على الرابط الصحيح [29:15] للقالب، وهو طويل [29:16] نوعًا ما. عند تشغيله، [29:17] سيتم تشغيل الخادم في [29:18] النهاية. وإذا أرسلتَ [29:20] طلبات حقيقية إلى هذا [29:22] الخادم، فسيتم [29:23] تقديمها لك من خلال [29:25] Ractor الرئيسي، وهذا [29:26] رائع جدًا. يُرجى [29:28] قراءة القالب قبل [29:29] تشغيله على جهازك. لقد [29:31] كُتب بعناية من قِبلي [29:32] أنا وزملائي، ولكنه [29:33] عبارة عن كود Ruby [29:35] عشوائي يُشغّل على [29:36] جهازك. لذا، يُرجى [29:37] قراءة القالب جيدًا [29:39] قبل تنفيذ أي شيء [29:40] رأيته على الشاشة في [29:42] مؤتمر. هذا كل شيء. ما [29:44] الخطوة التالية؟ نريد [29:46] مواصلة توسيع دعم Ractor [29:48] في Rails. نريد جعل [29:49] النظام البيئي أكثر [29:50] توافقًا مع Ractor، مثل [29:51] المكتبات البرمجية (gems [29:53] ). ونريد العمل على جعل [29:54] التطبيقات الحقيقية [29:55] آمنة للاستخدام مع Ractor [29:56] . سنعمل على كل هذه [29:57] الأمور في Shopify خلال [29:58] العام المقبل، ولكن [29:59] الأمر المثير هو أن [30:00] بإمكانكم أنتم في [30:01] المجتمع القيام بكل [30:02] هذا أيضًا. لذا، [30:03] أنشئوا تطبيقًا [30:03] جديدًا باستخدام [30:04] قالبنا، وأضيفوا إليه [30:06] بعض الوظائف الجديدة. [30:07] من المحتمل أن يظهر [30:08] خطأ في عزل Ractor في مكان [30:10] ما، وبذلك تكون [30:11] مساهمتكم التالية في [30:12] Rails جاهزة. إذا كنتم [30:14] تساهمون في أي مكتبات [30:15] برمجية (gems) أو [30:16] تملكونها، فاعملوا [30:17] على جعلها متوافقة مع [30:18] Ractor. وإذا كان لديكم [30:19] مشروع جانبي أو تطبيق [30:20] صغير، فابحثوا في [30:21] كيفية جعله آمنًا [30:22] للاستخدام مع Ractor. [30:23] تتميز البرامج الآلية [30:24] بقدرتها على اكتشاف [30:25] هذه المشاكل وإصلاحها [30:27] ، ويمكنكم على الأرجح [30:28] إحراز تقدم سريع. [30:29] أتمنى حقًا أن أكون [30:30] أنا أو أحد زملائي أو [30:31] أحدكم على خشبة المسرح [30:32] العام المقبل لنلقي [30:34] محاضرة حول كيفية [30:35] استخدامنا لـ Ractor في [30:36] بيئة الإنتاج. سيكون [30:37] ذلك رائعًا حقًا. وهذا [30:39] كل ما لدي اليوم. أود [30:41] أن أشكر جميع [30:41] المتعاونين معي الذين [30:42] ساهموا في كتابة الكود [30:43] ، والذين أجروا نقاشات [30:44] مثمرة وقدموا ملاحظات [30:45] قيّمة جعلت هذا العمل [30:46] ممكناً. وشكراً لكم [30:47] جميعاً على حسن [30:48] استماعكم.