0Pricing
Scala for Backend Engineering & Functional Programming · درس

تشغيل خط أنابيب

حوّل الرسم البياني إلى تنفيذ ونفّذه

تشغيل خط أنابيب درس مجاني في Scala for Backend Engineering & Functional Programming على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Scala for Backend Engineering & Functional Programming، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Scala for Backend Engineering & Functional Programming 4 دروس في المجموع.

من المخطط إلى التنفيذ

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

لا يحدث شيء حتى تشغّل الرسم البياني صراحةً، وهذا ما يجعل Akka Streams قابلة للتركيب وإعادة الاستخدام.

ActorSystem

يتطلب التجسيد وجود ActorSystem، الذي يوفر مؤشرات الترابط والموزّع اللذين يدعمان مراحل التدفق. وفي Akka الحديثة، يعمل النظام أيضًا بوصفه المُجسِّد الضمني.

يخدم ActorSystem واحد عادةً تطبيقًا كاملًا والعديد من التدفقات المتزامنة.

import akka.actor.ActorSystem

implicit val system: ActorSystem =
  ActorSystem("data-pipeline")
import system.dispatcher // ExecutionContext

runWith

الطريقة المباشرة لتشغيل Source هي runWith، إذ يربط Sink ويجسّدهما في خطوة واحدة، ويعيد القيمة الناتجة عند التشغيل الخاصة بذلك Sink.

تكون النتيجة هنا Future[Int] تكتمل بالمجموع عند انتهاء التدفق.

import akka.stream.scaladsl.{Source, Sink}
import scala.concurrent.Future

val total: Future[Int] =
  Source(1 to 100).runWith(Sink.fold(0)(_ + _))

تشغيل RunnableGraph

إذا كنت قد أنشأت مسبقًا RunnableGraph مغلقًا باستخدام to أو toMat، فاستدعِ run() لتجسيده. وتكون القيمة المعادة هي أي قيمة ناتجة عند التشغيل احتفظ بها الرسم البياني.

يفصل ذلك بوضوح بين إنشاء المسار وتنفيذه.

import akka.stream.scaladsl.Keep
import scala.concurrent.Future

val graph =
  Source(1 to 100)
    .toMat(Sink.fold(0)(_ + _))(Keep.right)

val result: Future[Int] = graph.run()

معاملات التشغيل الاختصارية

توفر Sources اختصارات مثل runForeach وrunFold وrunReduce، إذ يربط كل منها Sink المقابل ويشغّله فورًا.

وهي مختصرة للعمليات النهائية الشائعة على Source.

import scala.concurrent.Future

val printed: Future[akka.Done] =
  Source(1 to 10).runForeach(println)

val sum: Future[Int] =
  Source(1 to 10).runFold(0)(_ + _)

التعامل مع Future الناتجة

تعيد Sinks النهائية قيمة Future تكتمل عند انتهاء التدفق أو فشله. سجّل دوال رد الاتصال باستخدام onComplete للاستجابة للنجاح أو الخطأ.

استخدم موزّع ActorSystem بوصفه ExecutionContext الضمني لدوال رد الاتصال هذه.

import scala.util.{Success, Failure}

total.onComplete {
  case Success(value) => println(s"Sum = $value")
  case Failure(ex)    => println(s"Failed: ${ex.getMessage}")
}

مسار واقعي

يقرأ مسار بيانات نموذجي من Source، ويحوّل البيانات باستخدام Flows، وينفّذ عمليات إدخال وإخراج غير متزامنة باستخدام mapAsync، ويجمع العناصر في دفعات باستخدام grouped، ثم يكتبها إلى Sink.

كل مرحلة صغيرة، ويُنفَّذ مسار المعالجة بأكمله باستدعاء run واحد.

val done =
  lineSource
    .map(parse)
    .mapAsync(4)(validate)
    .grouped(500)
    .runWith(bulkWriteSink)

إعادة تشغيل التدفقات الفاشلة

لزيادة الاعتمادية، غلّف Source أو Flow باستخدام RestartSource.withBackoff، بحيث تؤدي حالات الفشل المؤقتة، مثل انقطاع الاتصال، إلى إعادة تشغيل تلقائية مع فترة انتظار أسية متزايدة.

يُبقي ذلك مسارات إدخال البيانات طويلة التشغيل قيد العمل من دون حاجة إلى إشراف يدوي.

import akka.stream.scaladsl.RestartSource
import akka.stream.RestartSettings
import scala.concurrent.duration._

val resilient = RestartSource.withBackoff(
  RestartSettings(1.second, 30.seconds, 0.2))(() => flakySource)

إيقاف التشغيل بسلاسة باستخدام KillSwitch

يتيح KillSwitch للتعليمات البرمجية الخارجية إيقاف تدفق قيد التشغيل بطريقة سليمة. أدرج KillSwitches.single عبر viaMat واحتفظ بقيمته المُجسَّدة لاستدعاء shutdown() لاحقًا.

وهذا ضروري للتدفقات طويلة التشغيل التي يجب إيقافها عند إيقاف تشغيل التطبيق.

import akka.stream.{KillSwitches, KillSwitch}
import akka.stream.scaladsl.Keep

val (switch, done) =
  source
    .viaMat(KillSwitches.single)(Keep.right)
    .toMat(Sink.ignore)(Keep.both)
    .run()
// later: switch.shutdown()

تحرير الموارد

عند خروج التطبيق، أنهِ ActorSystem لتحرير خيوطه. اربط استدعاء terminate بـ Future اكتمال التدفق، حتى يتم إيقاف التشغيل بطريقة منظمة.

يؤدي تسرّب ActorSystem إلى إبقاء JVM قيد التشغيل وإبقاء الموارد مفتوحة.

done.onComplete { _ =>
  system.terminate()
}

إعادة استخدام Materializer

يؤدي تجسيد المخطط نفسه عدة مرات إلى إنشاء تدفقات مستقلة قيد التشغيل، تتشارك موارد ActorSystem. ويظل المخطط نفسه غير قابل للتغيير وخاليًا من الآثار الجانبية.

يتيح ذلك تعريف مسار معالجة مرة واحدة وتشغيله عند الطلب لكل مهمة واردة.

val blueprint =
  Source(1 to 5).toMat(Sink.seq)(Keep.right)

val run1 = blueprint.run()
val run2 = blueprint.run() // independent execution

تحقق سريع

فكّروا فيما يلزم لكي يعالج التدفق العناصر فعليًا.

خلاصة

يعني تشغيل مسار المعالجة تجسيد مخطط باستخدام ActorSystem عبر run أو runWith أو المعاملات المساعدة، حيث يعيد كل منها نتيجة من نوع Future.

تعرّفتم على مسارات معالجة واقعية متعددة المراحل، وإعادة التشغيل التلقائية مع فترة انتظار متزايدة، والإيقاف السلس باستخدام KillSwitch، وتنظيف الموارد عبر system.terminate()، وإعادة استخدام آمنة لمخطط غير قابل للتغيير عبر عمليات تشغيل مستقلة.

الأسئلة الشائعة

هل درس «تشغيل خط أنابيب» مجاني؟

نعم — نص درس «تشغيل خط أنابيب» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Scala for Backend Engineering & Functional Programming، انتقل إلى CoddyKit PRO. تتضمن دورة Scala for Backend Engineering & Functional Programming 4 دروس في المجموع.

ماذا ستتعلم في «تشغيل خط أنابيب»؟

حوّل الرسم البياني إلى تنفيذ ونفّذه تتمرن على Scala for Backend Engineering & Functional Programming مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Scala for Backend Engineering & Functional Programming؟

لا تُشترط خبرة سابقة. Scala for Backend Engineering & Functional Programming على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.

كم من الوقت يستغرق درس «تشغيل خط أنابيب»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Scala for Backend Engineering & Functional Programming هذا؟

نعم. كل درس في Scala for Backend Engineering & Functional Programming يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. Source وFlow وSink
  2. تحويل التدفقات
  3. التحكم في الضغط
  4. تشغيل خط أنابيب
← العودة إلى Scala for Backend Engineering & Functional Programming