Sdílet prostřednictvím


Zpracování chyb v Durable Functions (Azure Functions)

Orchestrace Durable Function jsou implementovány v kódu a mohou používat integrované funkce zpracování chyb programovacího jazyka. Ve skutečnosti nejsou k dispozici žádné nové koncepty, které byste se měli naučit přidávat do orchestrací zpracování chyb a kompenzaci. Existuje však několik chování, o které byste měli vědět.

Poznámka:

Verze 4 programovacího modelu Node.js pro Azure Functions je obecně dostupná. Nový model v4 je navržený tak, aby měl flexibilnější a intuitivnější prostředí pro vývojáře v JavaScriptu a TypeScriptu. Další informace o rozdílech mezi v3 a v4 najdete v průvodci migrací.

V následujících fragmentech kódu JavaScript (PM4) označuje programovací model V4, nové prostředí.

Chyby ve funkcích aktivit a dílčích orchestracích

V Durable Functions jsou neošetřené výjimky vyvolané v rámci funkcí aktivit nebo dílčí orchestrace zařazovány zpět do funkce orchestrátoru pomocí standardizovaných typů výjimek.

Představte si například následující funkci orchestrátoru, která provádí převod fondu mezi dvěma účty:

V jazyce C# v procesu Durable Functions jsou neošetřené výjimky vyvolány jako functionFailedException.

Zpráva o výjimce obvykle identifikuje, které funkce aktivit nebo dílčí orchestrace způsobily selhání. Pokud chcete získat přístup k podrobnějším informacím o chybách, zkontrolujte InnerException vlastnost.

[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
            });
    }
}

Poznámka:

Předchozí příklady jazyka C# jsou pro Durable Functions 2.x. Pro Durable Functions 1.x je nutné použít DurableOrchestrationContext místo IDurableOrchestrationContext. Další informace o rozdílech mezi verzemi najdete v článku o verzích Durable Functions.

Pokud první volání funkce CreditAccount selže, funkce orchestrátoru vyrovnává kredity zpět do zdrojového účtu.

Chyby ve funkcích entit

Chování výjimečného zpracování u funkcí entit se liší podle modelu hostování Durable Functions.

V Durable Functions využívajících režim v procesu jazyka C# jsou původní typy výjimek vyvolané funkcemi entit předávány přímo orchestrátoru.

[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;
    }
}

Automatické opakování při selhání

Při volání funkcí aktivity nebo dílčí orchestrace můžete zadat zásady automatického opakování. Následující příklad se pokusí volat funkci až třikrát a mezi jednotlivými opakováními počká 5 sekund:

[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);

    // ...
}

Poznámka:

Předchozí příklady jazyka C# jsou pro Durable Functions 2.x. Pro Durable Functions 1.x je nutné použít DurableOrchestrationContext místo IDurableOrchestrationContext. Další informace o rozdílech mezi verzemi najdete v článku o verzích Durable Functions.

Volání funkce aktivity v předchozím příkladu přebírá parametr pro konfiguraci zásady automatického opakování. Pro přizpůsobení zásad automatického opakování existuje několik možností:

  • Maximální počet pokusů: Maximální počet pokusů. Pokud je nastavená hodnota 1, nebude se opakovat.
  • První interval opakování: Doba čekání před prvním pokusem o opakování.
  • Koeficient zpětného odsud: Koeficient použitý k určení míry zvýšení zásady. Výchozí hodnota je 1.
  • Maximální interval opakování: Maximální doba čekání mezi opakovanými pokusy.
  • Časový limit opakování: Maximální doba strávená opakováním. Výchozí chování je opakovat po neomezenou dobu.

Vlastní obslužné rutiny opakování

Při použití .NET nebo Javy máte také možnost implementovat obslužné rutiny opakování v kódu. To je užitečné v případě, že zásady deklarativních opakování nejsou dostatečně výrazné. U jazyků, které nepodporují vlastní obslužné rutiny opakování, máte stále možnost implementovat zásady opakování pomocí smyček, zpracování výjimek a časovačů pro vkládání zpoždění mezi opakováními.

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);

Časové limity funkcí

Volání funkce v rámci funkce orchestrátoru můžete chtít opustit, pokud dokončení trvá příliš dlouho. Správným způsobem, jak to udělat dnes, je vytvoření trvalého časovače s "libovolným" selektorem úkolů, jak je znázorněno v následujícím příkladu:

[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;
        }
    }
}

Poznámka:

Předchozí příklady jazyka C# jsou pro Durable Functions 2.x. Pro Durable Functions 1.x je nutné použít DurableOrchestrationContext místo IDurableOrchestrationContext. Další informace o rozdílech mezi verzemi najdete v článku o verzích Durable Functions.

Poznámka:

Tento mechanismus ve skutečnosti neukončí probíhající provádění funkce aktivity. Místo toho jednoduše umožňuje funkci orchestrátoru ignorovat výsledek a pokračovat. Další informace najdete v dokumentaci k časovačům .

Neošetřené výjimky

Pokud funkce orchestrátoru selže s neošetřenou výjimkou, zaprotokolují se podrobnosti o výjimce a instance se dokončí se stavem Failed .

Zahrnout vlastní vlastnosti výjimky pro FailureDetails (izolované rozhraní .NET)

Při spouštění pracovních postupů Durable Task v izolovaném modelu .NET se selhání úkolů automaticky serializují do objektu FailureDetails. Ve výchozím nastavení tento objekt zahrnuje standardní pole, například:

  • ErrorType – název typu výjimky
  • Zpráva – zpráva o výjimce
  • StackTrace – serializované trasování zásobníku
  • InnerFailure – vnořený objekt FailureDetails pro rekurzivní vnitřní výjimky

Počínaje Microsoft.Azure.Functions.Worker.Extensions.DurableTask v1.9.0 můžete toto chování rozšířit implementací IExceptionPropertiesProvider (definovaného v Microsoft.DurableTask.Worker, počínaje balíčkem v1.16.1). Tento zprostředkovatel definuje, které typy výjimek a které z jejich vlastností by měly být zahrnuty ve slovníku FailureDetails.Properties.

Poznámka:

  • Tato funkce je dostupná pouze v izolovaném prostředí .NET . Podpora pro Javu se přidá v budoucí verzi.
  • Ujistěte se, že používáte Microsoft.Azure.Functions.Worker.Extensions.DurableTask verze 1.9.0 nebo novější.
  • Ujistěte se, že používáte Microsoft.DurableTask.Worker verze 1.16.1 nebo novější.

Implementace zprostředkovatele vlastností výjimek

Implementujte vlastní IExceptionPropertiesProvider pro extrakci a vrácení vybraných vlastností pro výjimky, které vás zajímají. Vrácený slovník bude serializován do pole Vlastnosti FailureDetails při vyvolání odpovídajícího typu výjimky.

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
        };
    }
}

Registrace poskytovatele

Zaregistrujte vlastního poskytovatele IExceptionPropertiesProvider v hostiteli pracovního procesu .NET Isolated, obvykle v 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();

Po registraci všechny výjimky, které odpovídají některému z popisovaných typů, budou automaticky zahrnovat nakonfigurované vlastnosti v jeho FailureDetails.

Ukázkový výstup Podrobnosti o selhání

Pokud dojde k výjimce, která odpovídá konfiguraci vašeho poskytovatele, orchestrace obdrží serializovanou strukturu FailureDetails takto:

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

Další kroky