مشاركة عبر


معالجة الأخطاء في Durable Functions (Azure Functions)

يتم تنفيذ عمليات تنظيم Durable Function في التعليمات البرمجية ويمكنها استخدام ميزات معالجة الأخطاء المضمنة في لغة البرمجة. لا توجد أي مفاهيم جديدة تحتاج إلى تعلم كيفية إضافة معالجة الأخطاء والتعويض في التزامن الخاص بك. ومع ذلك، هناك بعض السلوكيات التي يجب أن تكون على علم بها.

إشعار

يتوفر الإصدار 4 من نموذج البرمجة Node.js ل Azure Functions بشكل عام. تم تصميم نموذج v4 الجديد للحصول على تجربة أكثر مرونة وبديهية لمطوري JavaScript وTypeScript. تعرف على المزيد حول الاختلافات بين v3 وv4 في دليل الترحيل.

في القصاصات البرمجية التالية، يشير JavaScript (PM4) إلى نموذج البرمجة V4، التجربة الجديدة.

أخطاء في وظائف النشاط والتنسيقات الفرعية

في الوظائف الدائمة، يتم تنظيم الاستثناءات غير المعالجة التي يتم طرحها داخل وظائف النشاط أو التنسيقات الفرعية مرة أخرى إلى وظيفة المنسق باستخدام أنواع الاستثناءات القياسية.

على سبيل المثال، ضع في اعتبارك وظيفة المنسق التالية التي تقوم بتحويل الأموال بين حسابين:

في Durable Functions C # قيد المعالجة، يتم طرح الاستثناءات غير المعالجة ك FunctionFailedException.

عادة ما تحدد رسالة الاستثناء وظائف النشاط أو التنسيقات الفرعية التي تسببت في الفشل. للوصول إلى معلومات أكثر تفصيلا عن الخطأ، افحص الموقع InnerException .

[FunctionName("TransferFunds")]
public static async Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    var transferDetails = context.GetInput<TransferOperation>();

    await context.CallActivityAsync("DebitAccount",
        new
        {
            Account = transferDetails.SourceAccount,
            Amount = transferDetails.Amount
        });

    try
    {
        await context.CallActivityAsync("CreditAccount",
            new
            {
                Account = transferDetails.DestinationAccount,
                Amount = transferDetails.Amount
            });
    }
    catch (FunctionFailedException)
    {
        // Refund the source account.
        // Another try/catch could be used here based on the needs of the application.
        await context.CallActivityAsync("CreditAccount",
            new
            {
                Account = transferDetails.SourceAccount,
                Amount = transferDetails.Amount
            });
    }
}

إشعار

أمثلة C# السابقة هي لـ Durable Functions 2.x. بالنسبة إلى Durable Functions 1.x، يتعين عليك استخدام DurableOrchestrationContext بدلاً من IDurableOrchestrationContext. لمزيدٍ من المعلومات حول الاختلافات بين الإصدارات، راجع مقالة إصدارات Durable Functions.

إذا فشل استدعاء دالة CreditAccount الأول، فإن دالة المنسق تعوض عن طريق إعادة رصيد الأموال إلى الحساب المصدر.

أخطاء في وظائف الكيان

يختلف سلوك معالجة الاستثناءات لوظائف الكيان استنادا إلى نموذج استضافة Durable Functions:

في Durable Functions باستخدام C# قيد المعالجة، يتم إرجاع أنواع الاستثناءات الأصلية التي طرحتها وظائف الكيان مباشرة إلى المنسق.

[FunctionName("Function1")]
public static async Task<string> RunOrchestrator(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    try
    {
        var entityId = new EntityId(nameof(Counter), "myCounter");
        await context.CallEntityAsync(entityId, "Add", 1);
    }
    catch (Exception ex)
    {
        // The exception type will be InvalidOperationException with the message "this is an entity exception".
    }
    return string.Empty;
}

[FunctionName("Counter")]
public static void Counter([EntityTrigger] IDurableEntityContext ctx)
{
    switch (ctx.OperationName.ToLowerInvariant())
    {
        case "add":
            throw new InvalidOperationException("this is an entity exception");
        case "get":
            ctx.Return(ctx.GetState<int>());
            break;
    }
}

إعادة المحاولة التلقائية عند الفشل

عند استدعاء دال النشاط أو دوال التزامن الفرعي، يمكنك تحديد سياسة إعادة المحاولة التلقائية. يحاول المثال التالي استدعاء دالة حتى ثلاث مرات وينتظر 5 ثوانٍ بين كل إعادة محاولة:

[FunctionName("TimerOrchestratorWithRetry")]
public static async Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    var retryOptions = new RetryOptions(
        firstRetryInterval: TimeSpan.FromSeconds(5),
        maxNumberOfAttempts: 3);

    await context.CallActivityWithRetryAsync("FlakyFunction", retryOptions, null);

    // ...
}

إشعار

أمثلة C# السابقة هي لـ Durable Functions 2.x. بالنسبة إلى Durable Functions 1.x، يتعين عليك استخدام DurableOrchestrationContext بدلاً من IDurableOrchestrationContext. لمزيدٍ من المعلومات حول الاختلافات بين الإصدارات، راجع مقالة إصدارات Durable Functions.

استدعاء دالة النشاط في المثال السابق يأخذ معلمة لتكوين نهج إعادة المحاولة التلقائي. هناك عدة خيارات لتخصيص سياسة إعادة المحاولة التلقائية:

  • الحد الأقصى للمحاولات: الحد الأقصى لعدد المحاولات. إذا تم تعيينه إلى 1، لن تكون هناك إعادة محاولة.
  • الفاصل الزمني الأول لإعادة المحاولة: مقدار الوقت المطلوب الانتظار قبل محاولة إعادة المحاولة الأولى.
  • معامل التراجع: المعامل المستخدم لتحديد معدل زيادة التراجع. تعود الإعدادات الافتراضية على 1.
  • الحد الأقصى للفاصل الزمني لإعادة المحاولة:الحد الأقصى لمقدار الوقت الذي يجب الانتظار فيه بين محاولات إعادة المحاولة.
  • مهلة إعادة المحاولة:الحد الأقصى لمقدار الوقت الذي تقضيه في إجراء عمليات إعادة المحاولة. السلوك الافتراضي هو إعادة المحاولة إلى أجل غير مسمى.

معالجات إعادة المحاولة المخصصة

عند استخدام .NET أو Java، لديك أيضا خيار تنفيذ معالجات إعادة المحاولة في التعليمات البرمجية. يكون هذا مفيدا عندما لا تكون سياسات إعادة المحاولة التعريفية معبرة بما فيه الكفاية. بالنسبة للغات التي لا تدعم معالجات إعادة المحاولة المخصصة، لا يزال لديك خيار تنفيذ نهج إعادة المحاولة باستخدام التكرارات الحلقية ومعالجة الاستثناءات والمؤقتات لإدخال التأخيرات بين عمليات إعادة المحاولة.

RetryOptions retryOptions = new RetryOptions(
    firstRetryInterval: TimeSpan.FromSeconds(5),
    maxNumberOfAttempts: int.MaxValue)
    {
        Handle = exception =>
        {
            // True to handle and try again, false to not handle and throw.
            if (exception is TaskFailedException failure)
            {
                // Exceptions from TaskActivities are always this type. Inspect the
                // inner Exception to get more details.
            }

            return false;
        };
    }

await ctx.CallActivityWithRetryAsync("FlakeyActivity", retryOptions, null);

مهلات الدوال

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

[FunctionName("TimerOrchestrator")]
public static async Task<bool> Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    TimeSpan timeout = TimeSpan.FromSeconds(30);
    DateTime deadline = context.CurrentUtcDateTime.Add(timeout);

    using (var cts = new CancellationTokenSource())
    {
        Task activityTask = context.CallActivityAsync("FlakyFunction");
        Task timeoutTask = context.CreateTimer(deadline, cts.Token);

        Task winner = await Task.WhenAny(activityTask, timeoutTask);
        if (winner == activityTask)
        {
            // success case
            cts.Cancel();
            return true;
        }
        else
        {
            // timeout case
            return false;
        }
    }
}

إشعار

أمثلة C# السابقة هي لـ Durable Functions 2.x. بالنسبة إلى Durable Functions 1.x، يتعين عليك استخدام DurableOrchestrationContext بدلاً من IDurableOrchestrationContext. لمزيدٍ من المعلومات حول الاختلافات بين الإصدارات، راجع مقالة إصدارات Durable Functions.

إشعار

لا تنهي هذه الآلية فعليا تنفيذ وظيفة النشاط قيد التقدم. بدلاً من ذلك، فإنه يسمح ببساطة دالة المنظم لتجاهل النتيجة والمضي قدمًا. لمزيد من المعلومات، راجع وثائق Timers.

استثناء غير معالج

إذا فشلت دالة المنسق باستثناء غير معالج، يتم تسجيل تفاصيل الاستثناء واكتمال المثيل بحالة Failed.

تضمين خصائص الاستثناء المخصص ل FailureDetails (.NET معزول)

عند تشغيل مهام سير عمل Durable Task في نموذج .NET Isolated ، يتم تسلسل حالات فشل المهام تلقائيا إلى كائن FailureDetails. بشكل افتراضي، يتضمن هذا الكائن حقول قياسية مثل:

  • ErrorType — اسم نوع الاستثناء
  • الرسالة - رسالة الاستثناء
  • StackTrace — تتبع المكدس المتسلسل
  • InnerFailure - كائن FailureDetails متداخل للاستثناءات الداخلية المتكررة

بدءا من Microsoft.Azure.Functions.Worker.Extensions.DurableTask v1.9.0، يمكنك توسيع هذا السلوك عن طريق تنفيذ IExceptionPropertiesProvider (محدد في حزمة Microsoft.DurableTask.Worker بدءا من الإصدار 1.16.1). يحدد هذا الموفر أنواع الاستثناءات وخصائصها التي يجب تضمينها في قاموس FailureDetails.Properties.

إشعار

  • تتوفر هذه الميزة في .NET Isolated فقط. ستتم إضافة دعم Java في إصدار مستقبلي.
  • تأكد من أنك تستخدم Microsoft.Azure.Functions.Worker.Extensions.DurableTask v1.9.0 أو أحدث.
  • تأكد من أنك تستخدم Microsoft.DurableTask.Worker v1.16.1 أو أحدث.

تنفيذ موفر خصائص الاستثناء

قم بتنفيذ IExceptionPropertiesProvider مخصص لاستخراج الخصائص المحددة وإرجاعها للاستثناءات التي تهتم بها. سيتم تسلسل القاموس الذي تم إرجاعه في حقل الخصائص الخاص ب FailureDetails عند طرح نوع استثناء مطابق.

using Microsoft.DurableTask.Worker;

public class CustomExceptionPropertiesProvider : IExceptionPropertiesProvider
{
    public IDictionary<string, object?>? GetExceptionProperties(Exception exception)
    {
        return exception switch
        {
            ArgumentOutOfRangeException e => new Dictionary<string, object?>
            {
                ["ParamName"] = e.ParamName,
                ["ActualValue"] = e.ActualValue
            },
            InvalidOperationException e => new Dictionary<string, object?>
            {
                ["CustomHint"] = "Invalid operation occurred",
                ["TimestampUtc"] = DateTime.UtcNow
            },
            _ => null // Other exception types not handled
        };
    }
}

تسجيل المزود

قم بتسجيل IExceptionPropertiesProvider المخصص في مضيف عامل .NET المعزول، عادة في Program.cs:

using Microsoft.DurableTask.Worker;
using Microsoft.Extensions.DependencyInjection;

var host = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults(builder =>
    {
        // Register custom exception properties provider
        builder.Services.AddSingleton<IExceptionPropertiesProvider, CustomExceptionPropertiesProvider>();
    })
    .Build();

host.Run();

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

فشل العينةإخراج التفاصيل

عند حدوث استثناء يطابق تكوين الموفر الخاص بك، يتلقى التنسيق بنية FailureDetails متسلسلة مثل هذا:

{
  "errorType": "TaskFailedException",
  "message": "Activity failed with an exception.",
  "stackTrace": "...",
  "innerFailure": {
    "errorType": "ArgumentOutOfRangeException",
    "message": "Specified argument was out of range.",
    "properties": {
      "ParamName": "count",
      "ActualValue": 42
    }
  }
}

الخطوات التالية