DeepSeek Harness: دورة حياة الإضافة: آلة حالة Fiber

آخر تحديث: 2026-08-31

كل إضافة في Cordis ليست كتلة كود ثابتة، بل كيان حي بدورة حياة — Fiber. فهم آلة حالة Fiber يعني فهم الرحلة الكاملة من "انتظار التحميل" إلى "التشغيل" إلى "الخروج بأمان"، وهو مفتاح كتابة إضافات متينة.

💡 نصيحة: القيمة الأساسية لـ Fiber هي "دورة حياة قابلة للملاحظة" — لكل انتقال حالة شروط تشغيل واضحة وآثار جانبية قابلة للملاحظة. أنت تعلم دائماً في أي حالة تكون الإضافة، ولماذا.

📋 المتطلبات المسبقة: أكمل 13-effect.md، تفهم التنظيف التلقائي و ctx.effect()

1. ما ستتعلمه

آلة حالة Fiber


2. مفهوم Fiber

(1) ما هو Fiber

Fiber هو تجريد Cordis لحالة تشغيل الإضافة — كل نسخة إضافة تقابل كائن Fiber يُسجّل في أي مرحلة من دورة الحياة تكون الإضافة حالياً.

TYPESCRIPT
interface Fiber {
  id: string
  name: string
  state: FiberState
  context: Context
  parent: Fiber | null
  children: Fiber[]
}

(2) لماذا نحتاج Fiber

بدون Fiber، الإضافات لها حالتان فقط: "مُحمّلة" و "غير مُحمّلة." لكن عملياً:

Fiber يوفر نموذج آلة حالة واضح لهذه الحالات الوسيطة.

(3) ▶ مثال 3

TEXT 📖 للعرض فقط
Fiber = "روح" الإضافة (معلومات الحالة)
Context = "جسد" الإضافة (الموارد والبيئة)

كل Fiber يحمل Context؛ دورة حياة Context مرتبطة بـ Fiber.


3. حالات دورة الحياة

(1) ▶ مثال 1

100%
stateDiagram-v2
    [*] --> pending: Plugin registered
    pending --> active: Dependencies ready + apply succeeds
    pending --> errored: apply fails
    active --> disposing: Unload requested
    errored --> active: Retry succeeds
    errored --> disposing: Retry abandoned
    disposing --> disposed: Cleanup complete

(2) معاني الحالات

الحالة المعنى ctx متاح قابل للعكس
pending انتظار الاعتماديات محدود
active يعمل بشكل طبيعي بالكامل
disposing يجري التنظيف للقراءة فقط
disposed مُدمّر غير متاح
errored فشل البدء غير متاح

(3) حالة pending

عندما تصرّح إضافة بـ inject لكن الاعتماديات لم تُسجّل بعد، يدخل Fiber حالة pending:

TYPESCRIPT
export const inject = ['tools']

// خدمة tools لم تُسجّل بعد → Fiber في حالة pending
// tools سُجّلت → Fiber ينتقل لـ active، يستدعي apply

أثناء pending:

(4) حالة active

بعد تنفيذ apply بنجاح، يدخل Fiber حالة active:

TYPESCRIPT
export function apply(ctx: Context) {
  // Fiber الآن active
  ctx.logger.info('I am alive!')
  
  ctx.on('session/created', (s) => {
    // يمكن استخدام جميع الخدمات بشكل طبيعي
  })
}

أثناء active:

(5) حالة disposing

بعد تلقي طلب إلغاء التحميل، يدخل Fiber حالة disposing ويبدأ تنظيف الموارد:

TEXT 📖 للعرض فقط
عملية disposing:
1. التوقف عن قبول طلبات جديدة
2. تنفيذ دوال تنظيف ctx.effect() بترتيب عكسي
3. إزالة مستمعي الأحداث تلقائياً
4. مسح المؤقتات
5. إلغاء تسجيل الأوامر والخدمات

(6) حالة disposed

بعد تنظيف جميع الموارد، يدخل Fiber حالة disposed:


4. إنشاء وتدمير Fiber

(1) توقيت الإنشاء

Fiber يُنشأ تلقائياً عند تسجيل إضافة:

TYPESCRIPT
// المنطق الداخلي للإطار (كود زائف)
function registerPlugin(plugin: PluginDefinition) {
  const fiber = new Fiber({
    id: generateId(),
    name: plugin.name,
    state: hasDeps(plugin) ? 'pending' : 'active'
  })
  
  if (fiber.state === 'active') {
    fiber.context = createContext(fiber)
    plugin.apply(fiber.context)
  }
}

(2) محفزات التدمير

تدمير Fiber يُحفّز بـ:

المحفّز الوصف
ctx.dispose() إلغاء تحميل نشط
تدمير Fiber الأب إلغاء تحميل متسلسل
إعادة تحميل تغيير الإعدادات Fiber القديم يُدمّر، Fiber جديد يُنشأ

(3) ▶ مثال 3

100%
graph TD
    TRIGGER[محفّز إلغاء التحميل] --> STOP[إيقاف الطلبات الجديدة]
    STOP --> CHILD[تدمير Fibers الأبناء]
    CHILD --> CLEAN[تنفيذ دوال التنظيف]
    CLEAN --> DISPOSED[تعليم كمُدمّر]

5. علاقات Fiber الأب-الابن

(1) الهيكل الهرمي

Fibers تدعم علاقات أب-ابن، مُشكّلة هياكل شجرية:

100%
graph TD
    ROOT[Root Fiber<br/>dsh-core] --> A[Plugin A Fiber]
    ROOT --> B[Plugin B Fiber]
    A --> A1[Sub-plugin A1]
    A --> A2[Sub-plugin A2]

(2) إنشاء علاقات أب-ابن

أنشئ Fibers أبناء عبر ctx.plugin():

TYPESCRIPT
export function apply(ctx: Context) {
  ctx.plugin({
    name: 'sub-plugin',
    apply(subCtx: Context) {
      subCtx.logger.info('I am a child fiber')
    }
  })
}

(3) التدمير المتسلسل

عندما يُدمّر Fiber الأب، تُدمّر جميع Fibers الأبناء تلقائياً:

TEXT 📖 للعرض فقط
إلغاء تحميل Plugin A:
  → أولاً تدمير Sub-plugin A1
  → ثم تدمير Sub-plugin A2
  → أخيراً تدمير Plugin A

ترتيب التدمير "الأبناء قبل الأب" هذا يضمن عدم كسر الاعتماديات.

(4) توريث النطاق

Fibers الأبناء ترث ctx الخاص بـ Fiber الأب:

TYPESCRIPT
// الخدمات المُسجّلة بالإضافة الأب يمكن الوصول لها من الإضافات الأبناء
export function apply(ctx: Context) {
  ctx.provide('parent-service', { ... })
  
  ctx.plugin({
    name: 'child',
    inject: ['parent-service'],
    apply(childCtx) {
      childCtx['parent-service'] // ✅ يمكن الوصول لخدمة الأب
    }
  })
}

6. معالجة الأخطاء والتراجع عن الحالة

(1) فشل apply

عندما يرمي apply استثناءً، يدخل Fiber حالة errored:

TYPESCRIPT
export function apply(ctx: Context) {
  throw new Error('initialization failed')
  // Fiber → errored
}

(2) إعادة المحاولة التلقائية

Cordis يُعيد المحاولة تلقائياً لـ Fibers في حالة errored:

TEXT 📖 للعرض فقط
المحاولة 1: apply() → throw Error → errored
المحاولة 2: (انتظار 1ث) apply() → throw Error → errored
المحاولة 3: (انتظار 2ث) apply() → throw Error → errored
المحاولة 4: (انتظار 4ث) apply() → success → active

فاصل إعادة المحاولة يستخدم تراجعاً أسيّاً: 1ث → 2ث → 4ث → 8ث → ... → أقصى 60ث.

(3) إعدادات استراتيجية إعادة المحاولة

TYPESCRIPT
export const Config = Schema.object({
  maxRetries: Schema.number().default(5).description('Max retry attempts'),
  retryInterval: Schema.number().default(1000).description('Initial retry interval (ms)')
})

(4) إعادة المحاولة يدوياً

TYPESCRIPT
ctx.on('fiber/errored', (fiber) => {
  ctx.logger.warn(`plugin ${fiber.name} errored, retrying...`)
  fiber.retry()
})

(5) أخطاء غير قابلة لإعادة المحاولة

بعض الأخطاء لا يجب إعادة محاولتها:

TYPESCRIPT
export function apply(ctx: Context) {
  if (!process.env.REQUIRED_VAR) {
    // خطأ إعدادات، إعادة المحاولة لن تفيد
    throw new NonRetryableError('REQUIRED_VAR is not set')
  }
}

(6) أخطاء مرحلة التنظيف

أخطاء مرحلة disposing لا تمنع Fiber من الانتقال لـ disposed، لكن تُسجّل:

TEXT 📖 للعرض فقط
[warn] cleanup error in plugin my-plugin: Connection already closed
[info] plugin my-plugin disposed (with 1 cleanup warnings)

7. عزل سياق Fiber

(1) كل Fiber له ctx مستقل

TYPESCRIPT
const fiberA = new Fiber({ name: 'plugin-a' })
const fiberB = new Fiber({ name: 'plugin-b' })

fiberA.context !== fiberB.context  // true

(2) حدود العزل

المورد معزول الوصف
مستمعو الأحداث كل Fiber يُسجّل بشكل مستقل
المؤقتات كل Fiber يُنظّف بشكل مستقل
الأوامر ⚠️ مشتركة عالمياً، لكن مع نطاقات
الخدمات مشتركة عالمياً
الإعدادات كل إضافة مستقلة

(3) موازنة مشاركة الخدمات والعزل

الخدمات مشتركة عالمياً — هذا قرار تصميم في Cordis. خدمة A التي سجّلتها إضافة A يمكن استخدامها بإضافة B عبر inject. إذا احتجت العزل، استخدم آلية النطاق (راجع 20-scope.md).

(4) استعلامات الحالة

TYPESCRIPT
// استعلام حالة Fiber
ctx.fiber.state           // 'active'
ctx.fiber.id              // 'fiber-abc-123'
ctx.fiber.parent          // Fiber الأب أو null
ctx.fiber.children        // Fiber[] الأبناء

❓ أسئلة شائعة

س ما العلاقة بين Fiber و Thread؟
ج لا علاقة. Fiber ليس خيط نظام تشغيل، بل وحدة حالة منطقية في Cordis. جميع Fibers تعمل في نفس حلقة أحداث Node.js.
س هل يمكنني إنشاء Fiber يدوياً؟
ج غير مُوصى به. عند تسجيل إضافات فرعية عبر ctx.plugin()، الإطار ينشئ Fibers تلقائياً.
س هل تستهلك الإضافات في حالة errored موارد؟
ج لا. Fiber في حالة errored لا يحتفظ بموارد ctx؛ فقط كائن Fiber نفسه (ذاكرة ضئيلة) يُحتفظ به لتتبع الحالة.
س هل يمكن لـ Fiber ابن البقاء بعد تدمير أبيه؟
ج لا. علاقات الأب-الابن هي اعتماديات قوية — تدمير الأب يُدمّر الأبناء دائماً. إذا احتجت دورات حياة مستقلة، لا تُنشئ علاقات أب-ابن.
س كيف أراقب جميع حالات Fiber؟
ج استمع لأحداث دورة حياة Fiber: typescript ctx.on('fiber/created', (fiber) => { ... }) ctx.on('fiber/active', (fiber) => { ... }) ctx.on('fiber/disposing', (fiber) => { ... }) ctx.on('fiber/disposed', (fiber) => { ... }) ctx.on('fiber/errored', (fiber) => { ... })
س عندما تُسبب تغييرات الإعدادات إعادة بناء Fiber، هل تُنفّذ دوال التنظيف القديمة؟
ج نعم. عند تغيير الإعدادات، Fiber القديم يمر بالتدفق الكامل disposing → disposed؛ جميع دوال التنظيف تُنفّذ. ثم يُنشأ Fiber جديد ويدخل pending/active.

📖 ملخص


📝 تمارين

1. ⭐ أساسي: اكتب إضافة تُخرج حالة Fiber ومعرفه الحالي في apply. ابدأها وتحقق من السجلات أن Fiber في حالة active.

2. ⭐⭐ متوسط: اكتب إضافة ترمي خطأً عمداً في apply (محاكاة فشل التهيئة). لاحظ حالة errored لـ Fiber وسلوك إعادة المحاولة. ثم أصلح الخطأ وتحقق أن Fiber يستعيد حالة active.

3. ⭐⭐⭐ تحدٍ: أنشئ هيكل Fiber أب-ابن: الإضافة الأب تُسجّل خدمة، إضافة الابن تستخدمها عبر inject. ألغِ تحميل الإضافة الأب وتحقق أن الابن يُدمّر متسلسلاً أيضاً. أخرج ترتيب التدمير في دوال التنظيف للتأكد من "الأبناء قبل الأب."

Web-Tutorial.com

فريق Web-Tutorial التقني

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

100%