Workflow Automation

حرفه‌ای شدن در Temporal: ساخت کارکردهای پایدار و بلندمدت

در چشم‌انداز سیستم‌های توزیع‌شده مدرن، نوشتن شغل‌های پس‌زمینه قابل اعتماد و فرآیندهای چندمرحله‌ای پیچیده به‌شکلی معروف دشوار است. رویکردهای سنتی اغلب به صف‌های پیام، ماشین‌های حالت یا شغل‌های cron ساده تکیه می‌کنند، اما این راه‌حل‌ها اغلب در زمینه دید، اشکال‌زدایی و مدیریت شکست‌های جزئی با مشکل مواجه می‌شوند. وارد شوید Temporal، یک پلتفرم اجرای کارکرد که به توسعه‌دهندگان اجازه می‌دهد منطق کسب‌وکار را به‌عنوان کد استاندارد بنویسند و بدون قربانی کردن تجربه توسعه‌دهنده، دوام و قابلیت اعتماد را تضمین کنند.

ارزش اصلی پیشنهادی Temporal «اجرای پایدار» (Durable Execution) است. برخلاف کد سنتی که تا زمان کرش یا تکمیل اجرا می‌شود، Temporal تاریخچه هر فراخوانی تابع را ثبت می‌کند. اگر فرآیندی در میانه اجرا کرش کند، Temporal می‌تواند فرآیند را از آخرین نقطه کنترل (checkpoint) بازیابی کرده و دقیقاً از همان‌جایی که متوقف شده بود ادامه دهد. این تغییر پارادایم، پیچیدگی مدیریت حالت را از توسعه‌دهنده به پلتفرم منتقل می‌کند.

معماری اصلی: کارکردها (Workflows) و فعالیت‌ها (Activities)

برای درک Temporal، باید بین دو مؤلفه اصلی آن تمایز قائل شوید: کارکردها (Workflows) و فعالیت‌ها (Activities).

  • کارکردها (Workflows): منطق هماهنگ‌سازی (Orchestration). آن‌ها ترتیب عملیات را تعریف می‌کنند، تلاش‌های مجدد (retries) را مدیریت می‌کنند و زمان‌بندی‌های اتمام (timeouts) را کنترل می‌کنند. نکته حیاتی این است که کد Workflow باید قطعی (deterministic) باشد. شما نمی‌توانید از تولیدکننده اعداد تصادفی، زمان‌های فعلی یا فراخوانی مستقیم پایگاه داده در داخل یک تابع Workflow استفاده کنید. به‌جای آن، از طریق فعالیت‌ها (Activities) با دنیای بیرون تعامل دارید.
  • فعالیت‌ها (Activities): کار واقعی دارای اثرات جانبی (side-effects). ارسال ایمیل، پرس‌وجو از پایگاه داده یا فراخوانی یک API خارجی در اینجا انجام می‌شود. فعالیت‌ها غیرقطعی هستند و توسط کارگران (workers) Temporal اجرا می‌شوند. اگر یک Activity شکست بخورد، Temporal می‌تواند بر اساس سیاست‌های پیکربندی‌شده به‌طور خودکار آن را دوباره امتحان کند، بدون اینکه کل Workflow را از ابتدا دوباره اجرا کند.

پیاده‌سازی عملی در Python

بیایید به یک مثال عملی از یک کارکرد پردازش پرداخت با استفاده از SDK پایتون Temporal نگاه کنیم. این الگو تضمین می‌کند که حتی اگر سرور بین شارژ کارت و به‌روزرسانی رکورد کاربر ری‌استارت شود، سیستم یکپارچه باقی بماند.


import time
from temporalio.client import Client
from temporalio.common import RetryPolicy
from temporalio.contrib.opentelemetry import TracingWorkflowInterceptor
from temporalio.worker import Worker
from temporalio.workflow import (
    ActivityError,
    define_workflow,
    workflow_activity,
    workflow_run,
    workflow_signal,
)

# 1. تعریف فعالیت‌ها (اثرات جانبی)
@workflow_activity(name="charge_credit_card")
async def charge_credit_card(amount: float, card_id: str) -> str:
    """شبیه‌سازی شارژ کارت اعتباری."""
    # در یک اپلیکیشن واقعی، این فراخوانی یک درگاه پرداخت است
    if amount > 1000:
        raise Exception("Payment declined: Limit exceeded")
    return f"tx_{int(time.time())}_{card_id}"

@workflow_activity(name="update_user_balance")
async def update_user_balance(user_id: str, transaction_id: str) -> None:
    """شبیه‌سازی به‌روزرسانی دفتر حساب داخلی کاربر."""
    # در یک اپلیکیشن واقعی، این به پایگاه داده نوشته می‌شود
    print(f"Updating balance for {user_id} with tx {transaction_id}")

# 2. تعریف کارکرد (هماهنگ‌سازی)
@define_workflow(name="PaymentProcessingWorkflow")
class PaymentProcessingWorkflow:
    async def __init__(self, amount: float, card_id: str, user_id: str):
        self.amount = amount
        self.card_id = card_id
        self.user_id = user_id

    async def run(self):
        """
        این کد قطعی است.
        Temporal این منطق را بر اساس تاریخچه رویدادها بازپخش (replay) می‌کند.
        """
        # اجرای فعالیت.
        # اگر این شکست بخورد، Temporal آن را بر اساس سیاست پیش‌فرض دوباره امتحان می‌کند.
        transaction_id = await self._activity(
            charge_credit_card, 
            self.amount, 
            self.card_id
        )
        
        # در صورت نیاز، برای دریافت سیگنال (مثلاً تأیید دستی) صبر کنید
        # await self._signal("approval_received")

        # به‌روزرسانی دفتر حساب
        await self._activity(
            update_user_balance, 
            self.user_id, 
            transaction_id
        )
        
        return transaction_id

    # کمکی برای فراخوانی فعالیت‌ها
    async def _activity(self, activity_func, *args, **kwargs):
        return await activity_func(*args, **kwargs)

# 3. اجرای یک Worker (این چیزی است که سرویس اپلیکیشن شما اجرا می‌کند)
async def main():
    client = await Client.connect("localhost:7233", namespace="default")
    
    async with Worker(
        client,
        task_queue="payment-queue",
        workflows=[PaymentProcessingWorkflow],
        activities=[
            charge_credit_card,
            update_user_balance
        ]
    ) as worker:
        print("Worker ready")
        await worker.run()

if __name__ == "__main__":
    import asyncio
    asyncio.run(main())

چرا Temporal را به جای گزینه‌های دیگر انتخاب کنیم؟

اگرچه سیستم‌هایی مانند AWS Step Functions یا Azure Durable Functions قابلیت‌های مشابهی ارائه می‌دهند، اما اغلب شما را به ارائه‌دهندگان ابری خاصی قفل می‌کنند یا مجبور می‌کنند کارکردها را از طریق JSON/YAML تعریف کنید. Temporal متن‌باز و قابل میزبانی خودکار (self-hostable) است و به شما کنترل کامل بر زیرساخت خود می‌دهد. علاوه بر این، از آنجا که کارکردها را در زبان‌های رایج (Python, Go, TypeScript, Java, .NET) می‌نویسید، می‌توانید از کدهای موجود، چارچوب‌های تست واحد و پشتیبانی IDE خود بهره ببرید.

یکی از قدرتمندترین ویژگی‌ها دید (Visibility) است. با Temporal، نیازی به ساخت یک داشبورد لاگ سفارشی برای مشاهده وضعیت کارکردهای خود ندارید. رابط کاربری Temporal به شما اجازه می‌دهد هر اجرای کارکرد را بازرسی کنید، ترتیب دقیق رویدادها را ببینید، کدی که اجرا شده است را مشاهده کنید و حتی سیگنال‌هایی را برای تغییر رفتار کارکردهای در حال اجرا به‌صورت بلادرنگ فعال کنید.

نتیجه‌گیری

Temporal سخت‌ترین مشکلات در سیستم‌های توزیع‌شده را حل می‌کند: قابلیت اعتماد، مشاهده‌پذیری (observability) و پیچیدگی. با انتزاع‌سازی مدیریت حالت و مدیریت شکست، به توسعه‌دهندگان اجازه می‌دهد بر منطق کسب‌وکار تمرکز کنند به‌جای کد چسب‌دار زیرساختی. چه در حال ساخت یک خط لوله داده، یک سیستم تکمیل سفارش یا یک تعامل پیچیده میکروسرویس باشید، Temporal یک بنیاد محکم برای خودکارسازی مقیاس‌پذیر و مقاوم ارائه می‌دهد. اگر با فرآیندهای بلندمدت سروکار دارید، زمان آن رسیده است که فراتر از شغل‌های cron بروید و شروع به تفکر بر اساس اجرای پایدار (Durable Execution) کنید.

Share: