في عالم تطوير الواجهات الخلفية الحديثة، أصبح بناء تطبيقات موزعة ومرنة أكثر تعقيداً. تتخلى البنى التقليدية الأحادية لصالح الخدمات المصغرة، مما يطرح تحديات جديدة تتعلق بإدارة الحالة، وتحمل الأعطال، والعمليات طويلة الأمد. هنا يأتي دور Temporal، وهو منصة مفتوحة المصدر صُممت لحل هذه المشكلات بالتحديد من خلال تبسيط بناء التطبيقات القابلة للتوسع والدائمة.
Temporal ليس مجرد مكتبة؛ بل هو منصة لبناء أنظمة موزعة يمكنها الصمود أمام الأعطال بسلاسة. فهو يوفر إطار عمل لكتابة الكود الذي يحدد المنطق التجاري طويل الأمد على شكل سير عمل (Workflows)، مما يضمن أنه حتى إذا انهار البنية التحتية الأساسية، فإن حالة العمل تبقى محفوظة ويمكن استئنافها من النقطة التي توقفت عندها بالضبط.
فهم المشكلة الأساسية: الطبيعة المؤقتة للبنية التحتية
فكر في سير عمل نموذجي لمعالجة المدفوعات. قد يتضمن ذلك التحقق من صحة بطاقة الائتمان، وتحصيل المبلغ من المستخدم، وتحديث المخزون، وإرسال بريد إلكتروني للتأكيد. إذا تم تنفيذ هذا المنطق في خدمة مصغرة قياسية وانهار الخادم بعد التحصيل ولكن قبل تحديث المخزون، فستجد نفسك أمام حالة جزئية. إعادة تشغيل العملية بأكملها قد تؤدي إلى تحصيل المبلغ من المستخدم مرتين.
يحل Temporal هذه المشكلة من خلال فصل منطق سير العمل عن محرك التنفيذ. يكتب المطور الكود الذي يصف ماذا يجب أن يحدث، ويتولى محرك Temporal التعامل مع كيف يحدث ذلك، بما في ذلك الاستمرارية، وإعادة المحاولة، والترتيب. يُشار إلى هذا غالباً باسم "تخليد" الحالة (Eternalization).
كيف يعمل Temporal: سير العمل، الأنشطة، والعملاء
لفهم Temporal، يجب أن تفهم تجريداته الأساسية الثلاث:
- سير العمل (Workflows): أجزاء منطقية طويلة الأمد ودائمة. تحدد التنسيق ويمكنها استدعاء الأنشطة.
- الأنشطة (Activities): وظائف قصيرة الأمد وتتحمل الأعطال تقوم بالعمل الفعلي، مثل استعلامات قاعدة البيانات أو طلبات HTTP.
- العملاء (Clients): نقطة الدخول لتطبيقك لبدء سير العمل والتواصل مع خادم Temporal.
مثال عملي: برمجة سير عمل دائم
لنلقِ نظرة على مثال عملي باستخدام لغة Go. تخيل سير عمل يعالج طلباً. نريد التأكد من أنه إذا فشل فحص المخزون، فإن النظام يعيد المحاولة قبل الانتقال إلى الخطوة التالية. بدون Temporal، فإن إدارة منطق إعادة المحاولة، وآجال الانتظار، واستمرارية الحالة يدوياً أمر عرضة للأخطاء. مع Temporal، يصبح الأمر إعلانياً (Declarative).
package main
import (
"context"
"fmt"
"go.temporal.io/sdk/client"
"go.temporal.io/sdk/workflow"
)
// ProcessOrderWorkflow هو تعريف سير العمل الدائم الخاص بنا
func ProcessOrderWorkflow(ctx workflow.Context, orderID string) error {
ao := workflow.ActivityOptions{
StartToCloseTimeout: 10 * time.Second,
}
ctx = workflow.WithActivityOptions(ctx, ao)
// فحص المخزون - إذا فشل هذا، سيعيد Temporal المحاولة تلقائياً
var inventoryOK bool
err := workflow.ExecuteActivity(ctx, CheckInventory, orderID).Get(ctx, &inventoryOK)
if err != nil {
return fmt.Errorf("failed to check inventory: %w", err)
}
if !inventoryOK {
return fmt.Errorf("item out of stock")
}
// تحصيل الدفع
err = workflow.ExecuteActivity(ctx, ChargePayment, orderID).Get(ctx, nil)
if err != nil {
return fmt.Errorf("payment failed: %w", err)
}
// تحديث قاعدة البيانات
err = workflow.ExecuteActivity(ctx, UpdateOrderStatus, orderID, "SHIPPED").Get(ctx, nil)
return err
}
لاحظ كيف يبدو الكود وكأنه برمجة متزامنة ومتسلسلة. ومع ذلك، تحت الغطاء، يسجل Temporal تاريخ الأحداث لكل خطوة. إذا انهار العملية بعد تحصيل الدفع، يقوم Temporal بإعادة تشغيل سير العمل من نقطة التفتيش الأخيرة، متجاوزاً فحص المخزون ولكن منفذاً منطق تحديث قاعدة البيانات بأمان.
لماذا تختار Temporal؟
يعزى اعتماد Temporal إلى قدرته على تجريد تعقيدات الأنظمة الموزعة. إنه يلغي الحاجة إلى آلات الحالة اليدوية، ومنطق إعادة المحاولة المخصص، وآليات قفل مستوى قاعدة البيانات للتنسيق. من خلال معاملة سير العمل كمواطنين من الدرجة الأولى، يمكن للمطورين التركيز على المنطق التجاري بدلاً من البنية التحتية الأساسية.
الخاتمة
يمثل Temporal تحولاً كبيراً في النموذج المعرفي لكيفية بناء أنظمة الواجهات الخلفية. فهو يمكّن المطورين من كتابة كود يتسم بالمتانة والقابلية للتوسع وسهولة الصيانة بشكل جوهري. من خلال اعتماد تنسيق سير العمل الدائم، يمكن للفرق تقليل الحمل التشغيلي وضمان بقاء تطبيقاتها متسقة حتى في مواجهة الأعطال الحتمية. بالنسبة للمطورين من المستوى المتوسط إلى المتقدم الذين يبحثون عن رفع موثوقية أنظمتهم، يُعد Temporal أداة لا غنى عنها في مجموعة أدوات الهندسة المعمارية الحديثة.