Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Sie implementieren Durable Functions Orchestrierungen im Code, sodass Sie die integrierten Fehlerbehandlungsfeatures Ihrer Sprache verwenden. Fehlerbehandlung und Kompensation erfordern keine neuen Konzepte, aber ein paar Orchestrierungsverhalten sind es wert, bekannt zu sein.
Hinweis
Version 4 des Node.js Programmiermodells für Azure Functions ist allgemein verfügbar. Das v4-Modell wurde entwickelt, um eine flexiblere und intuitivere Oberfläche für JavaScript- und TypeScript-Entwickler bereitzustellen. Weitere Informationen zu den Unterschieden zwischen v3 und v4 finden Sie im Migrationshandbuch.
In den folgenden Codeausschnitten bezeichnet JavaScript (PM4) das Programmiermodell v4, die neue Oberfläche.
Apps, die Clouddienste verwenden, müssen Fehler behandeln, und wiederholte Versuche auf Clientseite sind ein wichtiger Bestandteil des Designs. Die SDKs für dauerhafte Aufgaben umfassen Unterstützung für die Fehlerbehandlung, Wiederholungen und Timeouts, die Ihnen beim Erstellen robuster Workflows helfen.
Fehler in Aktivitätsfunktionen und Suborchestrierungen
In dauerhaften Funktionen werden unbehandelte Ausnahmen, die innerhalb von Aktivitätsfunktionen oder Unterorchestrierungen ausgelöst werden, mithilfe standardisierter Ausnahmetypen zurück zur Orchestratorfunktion gemarshallt.
Die folgende Orchestratorfunktion überträgt Guthaben zwischen zwei Konten:
Isoliertes Arbeitsmodell
n Durable Functions C# Isolated werden unbehandelte Ausnahmen als TaskFailedException angezeigt.
Die Ausnahmemeldung identifiziert in der Regel, welche Aktivitätsfunktionen oder Sub-Orchestrierungen den Fehler verursacht haben. Um auf detailliertere Fehlerinformationen zuzugreifen, überprüfen Sie die FailureDetails-Eigenschaft .
[FunctionName("TransferFunds")]
public static async Task Run(
[OrchestrationTrigger] TaskOrchestrationContext context, TransferOperation transferDetails)
{
await context.CallActivityAsync("DebitAccount",
new
{
Account = transferDetails.SourceAccount,
Amount = transferDetails.Amount
});
try
{
await context.CallActivityAsync("CreditAccount",
new
{
Account = transferDetails.DestinationAccount,
Amount = transferDetails.Amount
});
}
catch (TaskFailedException)
{
// 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
});
}
}
Hinweis
- Die Ausnahmemeldung identifiziert in der Regel, welche Aktivitätsfunktionen oder Sub-Orchestrierungen den Fehler verursacht haben. Um auf detailliertere Fehlerinformationen zuzugreifen, überprüfen Sie die
FailureDetailsEigenschaft. - Standardmäßig enthält
FailureDetailsden Fehlertyp, die Fehlermeldung, die Stapelspur und alle geschachtelten inneren Ausnahmen, wobei jede als rekursivesFailureDetails-Objekt dargestellt wird. Informationen zum Hinzufügen zusätzlicher Ausnahmeeigenschaften zur Fehlerausgabe finden Sie unter Benutzerdefinierte Ausnahmeeigenschaften für FailureDetails einbeziehen (.NET Isolated).
In-Process Model
In Durable Functions C#-In-Process werden unbehandelte Ausnahmen als FunctionFailedException ausgelöst.
Die Ausnahmemeldung enthält üblicherweise die Aktivitätsfunktion oder die Unterorchestrierung, die fehlgeschlagen ist. Ausführliche Informationen erhalten Sie unter 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
});
}
}
Hinweis
In den vorherigen C#-Beispielen wird Durable Functions 2.x verwendet. Verwenden Sie für Durable Functions 1.x DurableOrchestrationContext anstelle von IDurableOrchestrationContext. Versionsunterschiede finden Sie im Artikel Durable Functions-Versionen.
Wenn der erste Funktionsaufruf von CreditAccount fehlschlägt, wird dies durch die Orchestratorfunktion kompensiert, indem die Gelder auf das Quellkonto zurücküberwiesen werden.
In den Durable Task SDKs werden unbehandelte Ausnahmen, die innerhalb von Aktivitäten oder Unterorchestrierungen ausgelöst werden, mithilfe des TaskFailedException-Typs an den Orchestrator zurückgesendet. Die Ausnahmeeigenschaft FailureDetails enthält detaillierte Informationen zum Fehler.
using Microsoft.DurableTask;
[DurableTask(nameof(TransferFundsOrchestration))]
public class TransferFundsOrchestration : TaskOrchestrator<TransferOperation, string>
{
public override async Task<string> RunAsync(
TaskOrchestrationContext context, TransferOperation transfer)
{
await context.CallActivityAsync(
nameof(DebitAccountActivity),
new AccountOperation { Account = transfer.SourceAccount, Amount = transfer.Amount });
try
{
await context.CallActivityAsync(
nameof(CreditAccountActivity),
new AccountOperation { Account = transfer.DestinationAccount, Amount = transfer.Amount });
}
catch (TaskFailedException ex)
{
// Log the failure details
var details = ex.FailureDetails;
// Compensate by refunding the source account
await context.CallActivityAsync(
nameof(CreditAccountActivity),
new AccountOperation { Account = transfer.SourceAccount, Amount = transfer.Amount });
return $"Transfer failed: {details.ErrorMessage}. Compensation completed.";
}
return "Transfer completed successfully";
}
}
Wenn die Aktivität CreditAccount fehlschlägt, fängt der Orchestrator die Ausnahme ab und kompensiert dies, indem er die Gelder dem Quellkonto wieder gutschreibt.
Fehler in Entitätsfunktionen
Die Ausnahmebehandlung in Entitätsfunktionen hängt vom Durable Functions Hostingmodell ab:
Isoliertes Arbeitsmodell
In Durable Functions C# isolated werden Ausnahmen von Entity-Funktionen von der Laufzeitumgebung in ein EntityOperationFailedException eingeschlossen. Um die ursprünglichen Ausnahmedetails abzurufen, überprüfen Sie die FailureDetails Eigenschaft.
[Function(nameof(MyOrchestrator))]
public static async Task<List<string>> MyOrchestrator(
[Microsoft.Azure.Functions.Worker.OrchestrationTrigger] TaskOrchestrationContext context)
{
var entityId = new Microsoft.DurableTask.Entities.EntityInstanceId(nameof(Counter), "myCounter");
try
{
await context.Entities.CallEntityAsync(entityId, "Add", 1);
}
catch (EntityOperationFailedException ex)
{
// Add your error handling
}
return new List<string>();
}
In-Process Model
In Durable Functions mit C#-In-Process geben Entitätsfunktionen ihre ursprünglichen Ausnahmetypen an den Orchestrator zurück.
[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 is 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;
}
}
Automatische Wiederholung bei einem Fehler
Wenn Sie Aktivitätsfunktionen oder Untergeordnete Orchestrierungsfunktionen aufrufen, geben Sie eine Richtlinie für den automatischen Wiederholungsvorgang an. Das folgende Beispiel ruft eine Funktion bis zu drei Mal auf und wartet fünf Sekunden zwischen Wiederholungsversuchen:
Isoliertes Arbeitsmodell
[FunctionName("TimerOrchestratorWithRetry")]
public static async Task Run([OrchestrationTrigger] TaskOrchestrationContext context)
{
var options = TaskOptions.FromRetryPolicy(new RetryPolicy(
maxNumberOfAttempts: 3,
firstRetryInterval: TimeSpan.FromSeconds(5)));
await context.CallActivityAsync("FlakyFunction", options: options);
// ...
}
In-Process Model
[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);
// ...
}
Hinweis
Die vorherigen C#-Beispiele gelten für Durable Functions 2.x. Für Durable Functions 1.x müssen Sie DurableOrchestrationContext anstelle von IDurableOrchestrationContext verwenden. Weitere Informationen zu den Unterschieden zwischen den Versionen finden Sie im Artikel Durable Functions versions.
Der Aktivitätsfunktionsaufruf im vorherigen Beispiel verwendet einen Parameter zum Konfigurieren einer automatischen Wiederholungsrichtlinie. Passen Sie die Richtlinie mit den folgenden Optionen an:
- Maximale Anzahl von Versuchen: Die maximale Anzahl von Versuchen. Bei Festlegung auf 1 treten keine Wiederholungen auf.
- First retry interval (Erstes Wiederholungsintervall): Die Zeitspanne bis zum Ablauf des ersten Wiederholungsversuchs.
- Backoff-Koeffizient: Der Koeffizient, der verwendet wird, um den Anstieg der Backoff-Intervalle zu bestimmen. Der Standardwert lautet 1.
- Max. Wiederholungsintervall: Die maximale Wartezeit zwischen Wiederholungsversuchen.
- Wiederholungs-Timeout: Die maximale Dauer, die für Wiederholungsversuche aufgewendet werden kann. Standardmäßig werden Wiederholungen auf unbestimmte Zeit fortgesetzt.
Die Durable Task SDKs enthalten alternative Planungsmethoden, die fehlgeschlagene Aktivitäten basierend auf einer bereitgestellten Richtlinie wiederholen. Diese Methoden sind nützlich für Aktivitäten, die Daten aus Webdiensten lesen oder idempotent-Schreibvorgänge in eine Datenbank ausführen.
using Microsoft.DurableTask;
[DurableTask(nameof(OrchestratorWithRetry))]
public class OrchestratorWithRetry : TaskOrchestrator<string, string>
{
public override async Task<string> RunAsync(
TaskOrchestrationContext context, string input)
{
// Configure retry policy
var retryPolicy = new RetryPolicy(
maxNumberOfAttempts: 3,
firstRetryInterval: TimeSpan.FromSeconds(5),
backoffCoefficient: 2.0,
maxRetryInterval: TimeSpan.FromMinutes(1),
retryTimeout: TimeSpan.FromMinutes(5));
var options = TaskOptions.FromRetryPolicy(retryPolicy);
// Call activity with automatic retry
string result = await context.CallActivityAsync<string>(
nameof(UnreliableActivity), input, options);
return result;
}
}
Die Optionen für die Wiederholungsrichtlinie sind:
- Maximale Anzahl von Versuchen: Die maximale Anzahl von Wiederholungsversuchen. Bei Festlegung auf 1 treten keine Wiederholungen auf.
- First retry interval (Erstes Wiederholungsintervall): Die Zeitspanne bis zum Ablauf des ersten Wiederholungsversuchs.
- Backoff-Koeffizient: Der Koeffizient, der verwendet wird, um den Anstieg der Backoff-Intervalle zu bestimmen. Der Standardwert lautet 1.
- Max. Wiederholungsintervall: Die maximale Wartezeit zwischen Wiederholungsversuchen.
- Retry timeout (Timeout wiederholen): die maximale Zeitspanne für das Ausführen von Wiederholungsversuchen.
Benutzerdefinierte Wiederholungshandler
Implementieren Sie in .NET und Java Wiederholungshandler im Code, wenn deklarative Wiederholungsrichtlinien nicht ausdrucksstark genug sind. In anderen Sprachen implementiert man die Wiederholungslogik mithilfe von Schleifen, Ausnahmebehandlung und Timern, um die Wiederholungsversuche zu verzögern.
Isoliertes Arbeitsmodell
TaskOptions retryOptions = TaskOptions.FromRetryHandler(retryContext =>
{
// Don't retry anything that derives from ApplicationException
if (retryContext.LastFailure.IsCausedBy<ApplicationException>())
{
return false;
}
// Quit after N attempts
return retryContext.LastAttemptNumber < 3;
});
try
{
await ctx.CallActivityAsync("FlakeyActivity", options: retryOptions);
}
catch (TaskFailedException)
{
// Case when the retry handler returns false...
}
In-Process Model
RetryOptions retryOptions = new RetryOptions(
firstRetryInterval: TimeSpan.FromSeconds(5),
maxNumberOfAttempts: int.MaxValue)
{
Handle = exception =>
{
// Return true to handle and retry, or false to throw.
if (exception is TaskFailedException failure)
{
// Exceptions from task activities are always this type. Inspect the
// inner exception for more details.
}
return false;
}
};
await ctx.CallActivityWithRetryAsync("FlakeyActivity", retryOptions, null);
Benutzerdefinierte Wiederholungshandler
Implementieren Sie in .NET und Java Wiederholungshandler im Code, um die Wiederholungslogik zu steuern. Dieser Ansatz ist nützlich, wenn deklarative Wiederholungsrichtlinien nicht ausdrucksstark genug sind.
using Microsoft.DurableTask;
[DurableTask(nameof(OrchestratorWithCustomRetry))]
public class OrchestratorWithCustomRetry : TaskOrchestrator<string, string>
{
public override async Task<string> RunAsync(
TaskOrchestrationContext context, string input)
{
// Custom retry handler with conditional logic
TaskOptions retryOptions = TaskOptions.FromRetryHandler(retryContext =>
{
// Don't retry if it's a validation error
if (retryContext.LastFailure.IsCausedBy<ArgumentException>())
{
return false;
}
// Retry up to 5 times for transient errors
return retryContext.LastAttemptNumber < 5;
});
try
{
return await context.CallActivityAsync<string>(
nameof(UnreliableActivity), input, retryOptions);
}
catch (TaskFailedException)
{
// All retries exhausted
return "Operation failed after all retries";
}
}
}
Funktion-Timeouts
Wenn ein Funktionsaufruf zu lange dauert, brechen Sie ihn in der Orchestratorfunktion ab. Erstellen Sie einen dauerhaften Timer mit einer any Aufgabenauswahl, wie im folgenden Beispiel gezeigt:
Isoliertes Arbeitsmodell
[Function("TimerOrchestrator")]
public static async Task<bool> Run([OrchestrationTrigger] TaskOrchestrationContext 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;
}
}
}
In-Process Model
[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;
}
}
}
Hinweis
Die vorherigen C#-Beispiele gelten für Durable Functions 2.x. Für Durable Functions 1.x müssen Sie DurableOrchestrationContext anstelle von IDurableOrchestrationContext verwenden. Weitere Informationen zu den Unterschieden zwischen den Versionen finden Sie im Artikel Durable Functions versions.
Hinweis
Dieser Mechanismus beendet die Ausführung der Aktivitätsfunktion nicht, die bereits ausgeführt wird. Sie ermöglicht es der Orchestratorfunktion, das Ergebnis zu ignorieren und fortzufahren. Weitere Informationen finden Sie unter Timer.
Timeouts für Aktivitäten
Wenn ein Aktivitätsaufruf zu lange dauert, können Sie aufhören zu warten. Erstellen Sie einen dauerhaften Timer und vergleichen Sie ihn mit der Bearbeitungsgeschwindigkeit der Aktivitätsaufgabe.
using Microsoft.DurableTask;
using System;
using System.Threading;
using System.Threading.Tasks;
[DurableTask(nameof(OrchestratorWithTimeout))]
public class OrchestratorWithTimeout : TaskOrchestrator<string, bool>
{
public override async Task<bool> RunAsync(
TaskOrchestrationContext context, string input)
{
TimeSpan timeout = TimeSpan.FromSeconds(30);
DateTime deadline = context.CurrentUtcDateTime.Add(timeout);
using var cts = new CancellationTokenSource();
Task activityTask = context.CallActivityAsync(nameof(SlowActivity), input);
Task timeoutTask = context.CreateTimer(deadline, cts.Token);
Task winner = await Task.WhenAny(activityTask, timeoutTask);
if (winner == activityTask)
{
// Activity completed in time - cancel the timer
cts.Cancel();
return true;
}
else
{
// Timeout occurred
return false;
}
}
}
Hinweis
Dieser Mechanismus beendet die Ausführung der Aktivität nicht, die bereits ausgeführt wird. Er ermöglicht es dem Orchestrator, das Ergebnis zu ignorieren und fortzufahren. Weitere Informationen finden Sie in der Dokumentation zu Timern.
Nicht behandelte Ausnahmen
Wenn eine Orchestratorfunktion mit einer unbehandelten Ausnahme fehlschlägt, protokolliert die Laufzeit die Ausnahmedetails, und die Instanz wird mit einem Failed Status abgeschlossen.
Einschließen von benutzerdefinierten Ausnahmeeigenschaften für FailureDetails (.NET Isolated)
In dauerhaften Aufgabenworkflows, die das .NET isolierten Modell verwenden, werden Vorgangsfehler in ein FailureDetails-Objekt serialisiert. Standardmäßig enthält das Objekt die folgenden Felder:
-
ErrorType— Ausnahmetypname -
Message— Ausnahmemeldung -
StackTrace—Serialisierte Stapelverfolgung -
InnerFailure—GeschachteltesFailureDetails-Objekt für interne Ausnahmen
Beginnend mit Microsoft. Azure. Functions.Worker.Extensions.DurableTask v1.9.0 können Sie dieses Verhalten erweitern, indem Sie IExceptionPropertiesProvider implementieren (definiert im Microsoft.DurableTask.Worker-Paket ab v1.16.1). Dieser Anbieter definiert, welche Ausnahmetypen und Eigenschaften in das FailureDetails.Properties Wörterbuch aufgenommen werden sollen.
Hinweis
- Dieses Feature ist nur in .NET Isolated verfügbar. Unterstützung für Java ist noch nicht verfügbar.
- Stellen Sie sicher, dass Sie Microsoft.Azure.Functions.Worker.Extensions.DurableTask v1.9.0 oder höher verwenden.
- Stellen Sie sicher, dass Sie Microsoft.DurableTask.Worker v1.16.1 oder höher verwenden.
Implementierung eines Anbieters für Ausnahmeeigenschaften
Implementieren Sie eine benutzerdefinierte IExceptionPropertiesProvider Eigenschaft zum Extrahieren und Zurückgeben ausgewählter Eigenschaften für die ausnahmen, die Sie interessieren. Das zurückgegebene Wörterbuch wird in das Feld Properties von FailureDetails serialisiert, wenn ein übereinstimmender Ausnahmetyp ausgelöst wird.
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
};
}
}
Hiermit wird der Anbieter registriert.
Registrieren Sie in Program.cs Ihren benutzerdefinierten IExceptionPropertiesProvider in Ihrem .NET isolierten Workerhost:
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();
Nachdem Sie den Anbieter registriert haben, werden bei jeder Ausnahme, die einem behandelten Typ entspricht, automatisch die konfigurierten Eigenschaften in die FailureDetails einbezogen.
Beispiel für eine FailureDetails-Ausgabe
Wenn eine Ausnahme auftritt, die der Konfiguration Ihres Anbieters entspricht, empfängt die Orchestrierung ein serialisiertes FailureDetails Objekt wie folgt:
{
"errorType": "TaskFailedException",
"message": "Activity failed with an exception.",
"stackTrace": "...",
"innerFailure": {
"errorType": "ArgumentOutOfRangeException",
"message": "Specified argument was out of range.",
"properties": {
"ParamName": "count",
"ActualValue": 42
}
}
}
Nicht behandelte Ausnahmen
Wenn ein Orchestrator aufgrund einer nicht behandelten Ausnahme fehlschlägt, protokolliert die Laufzeit die Ausnahmedetails, und die Instanz wird mit einem Failed Status abgeschlossen. Die TaskFailedException hat eine FailureDetails-Eigenschaft, die den Fehlertyp, die Meldung und die Stapelverfolgung enthält.