Orkestrasi Durable Functions diimplementasikan dalam kode dan dapat menggunakan fitur penanganan kesalahan bawaan bahasa pemrograman. Benar-benar tidak ada konsep baru yang perlu Anda pelajari untuk menambahkan penanganan kesalahan dan kompensasi ke dalam orkestrasi Anda. Namun, ada beberapa perilaku yang harus Anda waspadai.
Catatan
Model pemrograman Node.js versi 4 untuk Azure Functions umumnya tersedia. Model v4 baru dirancang untuk memiliki pengalaman yang lebih fleksibel dan intuitif untuk pengembang JavaScript dan TypeScript. Pelajari selengkapnya tentang perbedaan antara v3 dan v4 dalam panduan migrasi.
Dalam cuplikan kode berikut, JavaScript (PM4) menunjukkan model pemrograman V4, pengalaman baru.
Kesalahan dalam fungsi aktivitas dan sub-orkestrasi
Dalam Durable Functions, pengecualian yang tidak tertangani yang terjadi dalam aktivitas fungsi atau sub-orkestrasi diarahkan kembali ke fungsi orkestrator menggunakan tipe pengecualian standar.
Misalnya, pertimbangkan fungsi orkestrator berikut yang melakukan transfer dana antara dua akun:
Dalam Durable Functions C# dalam proses, pengecualian yang tidak tertangani dilemparkan sebagai FunctionFailedException.
Pesan pengecualian biasanya mengidentifikasi fungsi aktivitas atau sub-orkestrasi mana yang menyebabkan kegagalan. Untuk mengakses informasi kesalahan yang lebih rinci, periksa properti InnerException tersebut.
[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
});
}
}
Catatan
Contoh C# sebelumnya adalah untuk Durable Functions 2.x. Untuk Durable Functions 1.x, Anda harus menggunakan DurableOrchestrationContext dan bukan IDurableOrchestrationContext. Untuk informasi selengkapnya tentang perbedaan antara versi, lihat artikel Versi Durable Functions.
Dalam Durable Functions C# Terisolasi, pengecualian yang tidak tertangani muncul sebagai TaskFailedException.
Pesan pengecualian biasanya mengidentifikasi fungsi aktivitas atau sub-orkestrasi mana yang menyebabkan kegagalan. Untuk mengakses informasi kesalahan yang lebih rinci, periksa properti FailureDetails .
[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
});
}
}
Catatan
- Pesan pengecualian biasanya mengidentifikasi fungsi aktivitas atau sub-orkestrasi mana yang menyebabkan kegagalan. Untuk mengakses informasi kesalahan yang lebih terperinci, periksa properti
FailureDetails.
- Secara default,
FailureDetails menyertakan jenis kesalahan, pesan kesalahan, pelacakan tumpukan, dan pengecualian berlapis (masing-masing direpresentasikan sebagai objek rekursif FailureDetails ). Jika Anda ingin menyertakan properti pengecualian tambahan dalam output kegagalan, lihat Menyertakan Properti Pengecualian Kustom untuk FailureDetails (.NET Isolated).
const df = require("durable-functions");
module.exports = df.orchestrator(function* (context) {
const transferDetails = context.df.getInput();
yield context.df.callActivity("DebitAccount", {
account: transferDetails.sourceAccount,
amount: transferDetails.amount,
});
try {
yield context.df.callActivity("CreditAccount", {
account: transferDetails.destinationAccount,
amount: transferDetails.amount,
});
} catch (error) {
// Refund the source account.
// Another try/catch could be used here based on the needs of the application.
yield context.df.callActivity("CreditAccount", {
account: transferDetails.sourceAccount,
amount: transferDetails.amount,
});
}
})
const df = require("durable-functions");
df.app.orchestration("transferFunds", function* (context) {
const transferDetails = context.df.getInput();
yield context.df.callActivity("debitAccount", {
account: transferDetails.sourceAccount,
amount: transferDetails.amount,
});
try {
yield context.df.callActivity("creditAccount", {
account: transferDetails.destinationAccount,
amount: transferDetails.amount,
});
} catch (error) {
// Refund the source account.
// Another try/catch could be used here based on the needs of the application.
yield context.df.callActivity("creditAccount", {
account: transferDetails.sourceAccount,
amount: transferDetails.amount,
});
}
});
import azure.functions as func
import azure.durable_functions as df
def orchestrator_function(context: df.DurableOrchestrationContext):
transfer_details = context.get_input()
yield context.call_activity('DebitAccount', {
'account': transfer_details['sourceAccount'],
'amount' : transfer_details['amount']
})
try:
yield context.call_activity('CreditAccount', {
'account': transfer_details['destinationAccount'],
'amount': transfer_details['amount'],
})
except:
yield context.call_activity('CreditAccount', {
'account': transfer_details['sourceAccount'],
'amount': transfer_details['amount']
})
main = df.Orchestrator.create(orchestrator_function)
Secara default, cmdlets di PowerShell tidak menimbulkan pengecualian yang dapat ditangkap menggunakan blok try/catch. Anda memiliki dua opsi untuk mengubah perilaku ini:
- Gunakan bendera
-ErrorAction Stop saat memanggil cmdlet, seperti Invoke-DurableActivity.
- Atur variabel preferensi
$ErrorActionPreference ke "Stop" dalam fungsi orkestrator sebelum memanggil cmdlet.
param($Context)
$ErrorActionPreference = "Stop"
$transferDetails = $Context.Input
Invoke-DurableActivity -FunctionName 'DebitAccount' -Input @{ account = transferDetails.sourceAccount; amount = transferDetails.amount }
try {
Invoke-DurableActivity -FunctionName 'CreditAccount' -Input @{ account = transferDetails.destinationAccount; amount = transferDetails.amount }
} catch {
Invoke-DurableActivity -FunctionName 'CreditAccount' -Input @{ account = transferDetails.sourceAccount; amount = transferDetails.amount }
}
Untuk informasi selengkapnya tentang penanganan kesalahan di PowerShell, lihat dokumentasi PowerShell Try-Catch-Finally.
@FunctionName("TransferFunds")
public void transferFunds(
@DurableOrchestrationTrigger(name = "ctx") TaskOrchestrationContext ctx) {
TransferOperation transfer = ctx.getInput(TransferOperation.class);
ctx.callActivity(
"DebitAccount",
new OperationArgs(transfer.sourceAccount, transfer.amount)).await();
try {
ctx.callActivity(
"CreditAccount",
new OperationArgs(transfer.destinationAccount, transfer.amount)).await();
} catch (TaskFailedException ex) {
// Refund the source account on failure
ctx.callActivity(
"CreditAccount",
new OperationArgs(transfer.sourceAccount, transfer.amount)).await();
}
}
Jika panggilan fungsi CreditAccount pertama gagal, fungsi orkestrator mengkompensasi dengan memberi kredit dana kembali ke akun sumber.
Kesalahan dalam fungsi entitas
Perilaku penanganan pengecualian untuk fungsi entitas berbeda berdasarkan model hosting Durable Functions:
Dalam Durable Functions menggunakan C# in-process, tipe pengecualian asli yang dilemparkan oleh fungsi entitas langsung dikembalikan ke orkestrator.
[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;
}
}
Dalam Durable Functions C# Terisolasi, pengecualian ditampilkan ke orkestrator sebagai EntityOperationFailedException. Untuk mengakses detail pengecualian asli, periksa properti FailureDetails.
[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>();
}
df.app.orchestration("counterOrchestration", function* (context) {
const entityId = new df.EntityId(counterEntityName, "myCounter");
try {
const currentValue = yield context.df.callEntity(entityId, "get");
if (currentValue < 10) {
yield context.df.callEntity(entityId, "add", 1);
}
} catch (err) {
context.log(`Entity call failed: ${err.message ?? err}`);
}
});
df.app.orchestration("counterOrchestration", function* (context) {
const entityId = new df.EntityId(counterEntityName, "myCounter");
try {
const currentValue = yield context.df.callEntity(entityId, "get");
if (currentValue < 10) {
yield context.df.callEntity(entityId, "add", 1);
}
} catch (err) {
context.log(`Entity call failed: ${err.message ?? err}`);
}
});
@myApp.orchestration_trigger(context_name="context")
def run_orchestrator(context):
try:
entityId = df.EntityId("Counter", "myCounter")
yield context.call_entity(entityId, "get")
return "finished"
except Exception as e:
# Add your error handling
Fungsi entitas saat ini tidak didukung di PowerShell.
Fungsi entitas saat ini tidak didukung di Java.
Percobaan otomatis saat kegagalan
Saat Anda memanggil fungsi aktivitas atau fungsi sub-orkestrasi, Anda dapat menentukan kebijakan percobaan kembali otomatis. Contoh berikut mencoba memanggil fungsi hingga tiga kali dan menunggu 5 detik di antara setiap percobaan:
[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);
// ...
}
Catatan
Contoh C# sebelumnya adalah untuk Durable Functions 2.x. Untuk Durable Functions 1.x, Anda harus menggunakan DurableOrchestrationContext dan bukan IDurableOrchestrationContext. Untuk informasi selengkapnya tentang perbedaan antara versi, lihat artikel Versi Durable Functions.
[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);
// ...
}
const df = require("durable-functions");
module.exports = df.orchestrator(function*(context) {
const firstRetryIntervalInMilliseconds = 5000;
const maxNumberOfAttempts = 3;
const retryOptions =
new df.RetryOptions(firstRetryIntervalInMilliseconds, maxNumberOfAttempts);
yield context.df.callActivityWithRetry("FlakyFunction", retryOptions);
// ...
});
const df = require("durable-functions");
df.app.orchestration("callActivityWithRetry", function* (context) {
const firstRetryIntervalInMilliseconds = 5000;
const maxNumberOfAttempts = 3;
const retryOptions = new df.RetryOptions(firstRetryIntervalInMilliseconds, maxNumberOfAttempts);
yield context.df.callActivityWithRetry("flakyFunction", retryOptions);
// ...
});
import azure.functions as func
import azure.durable_functions as df
def orchestrator_function(context: df.DurableOrchestrationContext):
first_retry_interval_in_milliseconds = 5000
max_number_of_attempts = 3
retry_options = df.RetryOptions(first_retry_interval_in_milliseconds, max_number_of_attempts)
yield context.call_activity_with_retry('FlakyFunction', retry_options)
main = df.Orchestrator.create(orchestrator_function)
param($Context)
$retryOptions = New-DurableRetryOptions `
-FirstRetryInterval (New-TimeSpan -Seconds 5) `
-MaxNumberOfAttempts 3
Invoke-DurableActivity -FunctionName 'FlakyFunction' -RetryOptions $retryOptions
@FunctionName("TimerOrchestratorWithRetry")
public void timerOrchestratorWithRetry(
@DurableOrchestrationTrigger(name = "ctx") TaskOrchestrationContext ctx) {
final int maxAttempts = 3;
final Duration firstRetryInterval = Duration.ofSeconds(5);
RetryPolicy policy = new RetryPolicy(maxAttempts, firstRetryInterval);
TaskOptions options = new TaskOptions(policy);
ctx.callActivity("FlakeyFunction", options).await();
// ...
}
Panggilan fungsi aktivitas dalam contoh sebelumnya mengambil parameter untuk mengonfigurasi kebijakan percobaan kembali otomatis. Ada beberapa opsi untuk menyesuaikan kebijakan percobaan kembali otomatis:
-
Max number of attempts:Jumlah maksimal dari upaya yang dicoba. Jika diatur ke 1, tidak akan ada percobaan ulang.
-
Interval percobaan pertama: Jumlah waktu untuk menunggu sebelum upaya coba lagi pertama.
-
Koefisien backoff: Koefisien yang digunakan untuk menentukan tingkat peningkatan backoff. Default ke 1.
-
Interval percobaan maksimal: Jumlah waktu maksimum untuk menunggu di antara upaya coba lagi.
-
Coba lagi waktu habis: Jumlah maksimum waktu yang harus dihabiskan untuk melakukan pengulangan. Perilaku default adalah mencoba kembali tanpa batas waktu.
Penangan coba lagi kustom
Saat menggunakan .NET atau Java, Anda juga memiliki opsi untuk mengimplementasikan handler coba lagi dalam kode. Ini berguna ketika kebijakan ulang deklaratif tidak cukup ekspresif. Untuk bahasa yang tidak mendukung penangan percobaan ulang kustom, Anda masih memiliki opsi untuk menerapkan kebijakan percobaan ulang menggunakan perulangan, penanganan pengecualian, dan pengatur waktu untuk memasukkan penundaan antara percobaan ulang.
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);
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...
}
JavaScript saat ini tidak mendukung penangan coba ulang kustom. Namun, Anda masih memiliki opsi untuk menerapkan logika coba lagi secara langsung di fungsi orkestrator menggunakan perulangan, penanganan pengecualian, dan timer untuk memasukkan penundaan di antara percobaan ulang.
JavaScript saat ini tidak mendukung penangan coba ulang kustom. Namun, Anda masih memiliki opsi untuk menerapkan logika coba lagi secara langsung di fungsi orkestrator menggunakan perulangan, penanganan pengecualian, dan timer untuk memasukkan penundaan di antara percobaan ulang.
Python saat ini tidak mendukung penangan percobaan ulang kustom. Namun, Anda masih memiliki opsi untuk menerapkan logika coba lagi secara langsung di fungsi orkestrator menggunakan perulangan, penanganan pengecualian, dan timer untuk memasukkan penundaan di antara percobaan ulang.
PowerShell saat ini tidak mendukung penanganan percobaan ulang kustom. Namun, Anda masih memiliki opsi untuk menerapkan logika coba lagi secara langsung di fungsi orkestrator menggunakan perulangan, penanganan pengecualian, dan timer untuk memasukkan penundaan di antara percobaan ulang.
RetryHandler retryHandler = retryCtx -> {
// Don't retry anything that derives from RuntimeException
if (retryCtx.getLastFailure().isCausedBy(RuntimeException.class)) {
return false;
}
// Quit after N attempts
return retryCtx.getLastAttemptNumber() < 3;
};
TaskOptions options = new TaskOptions(retryHandler);
try {
ctx.callActivity("FlakeyActivity", options).await();
} catch (TaskFailedException ex) {
// Case when the retry handler returns false...
}
Batas waktu fungsi
Anda mungkin ingin meninggalkan panggilan fungsi dalam fungsi orkestrator jika terlalu lama untuk diselesaikan. Cara yang tepat untuk melakukannya hari ini adalah dengan membuat timer tahan lama dengan pemilih tugas "apa saja", seperti dalam contoh berikut:
[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;
}
}
}
Catatan
Contoh C# sebelumnya adalah untuk Durable Functions 2.x. Untuk Durable Functions 1.x, Anda harus menggunakan DurableOrchestrationContext dan bukan IDurableOrchestrationContext. Untuk informasi selengkapnya tentang perbedaan antara versi, lihat artikel Versi Durable Functions.
[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;
}
}
}
const df = require("durable-functions");
const moment = require("moment");
module.exports = df.orchestrator(function*(context) {
const deadline = moment.utc(context.df.currentUtcDateTime).add(30, "s");
const activityTask = context.df.callActivity("FlakyFunction");
const timeoutTask = context.df.createTimer(deadline.toDate());
const winner = yield context.df.Task.any([activityTask, timeoutTask]);
if (winner === activityTask) {
// success case
timeoutTask.cancel();
return true;
} else {
// timeout case
return false;
}
});
const df = require("durable-functions");
const { DateTime } = require("luxon");
df.app.orchestration("timerOrchestrator", function* (context) {
const deadline = DateTime.fromJSDate(context.df.currentUtcDateTime).plus({ seconds: 30 });
const activityTask = context.df.callActivity("flakyFunction");
const timeoutTask = context.df.createTimer(deadline.toJSDate());
const winner = yield context.df.Task.any([activityTask, timeoutTask]);
if (winner === activityTask) {
// success case
timeoutTask.cancel();
return true;
} else {
// timeout case
return false;
}
});
import azure.functions as func
import azure.durable_functions as df
from datetime import datetime, timedelta
def orchestrator_function(context: df.DurableOrchestrationContext):
deadline = context.current_utc_datetime + timedelta(seconds = 30)
activity_task = context.call_activity('FlakyFunction')
timeout_task = context.create_timer(deadline)
winner = yield context.task_any(activity_task, timeout_task)
if winner == activity_task:
timeout_task.cancel()
return True
else:
return False
main = df.Orchestrator.create(orchestrator_function)
param($Context)
$expiryTime = New-TimeSpan -Seconds 30
$activityTask = Invoke-DurableActivity -FunctionName 'FlakyFunction'-NoWait
$timerTask = Start-DurableTimer -Duration $expiryTime -NoWait
$winner = Wait-DurableTask -Task @($activityTask, $timerTask) -NoWait
if ($winner -eq $activityTask) {
Stop-DurableTimerTask -Task $timerTask
return $True
}
else {
return $False
}
@FunctionName("TimerOrchestrator")
public boolean timerOrchestrator(
@DurableOrchestrationTrigger(name = "ctx") TaskOrchestrationContext ctx) {
Task<Void> activityTask = ctx.callActivity("SlowFunction");
Task<Void> timeoutTask = ctx.createTimer(Duration.ofMinutes(30));
Task<?> winner = ctx.anyOf(activityTask, timeoutTask).await();
if (winner == activityTask) {
// success case
return true;
} else {
// timeout case
return false;
}
}
Catatan
Mekanisme ini sebenarnya tidak mengakhiri eksekusi fungsi aktivitas yang sedang berlangsung. Sebaliknya, itu hanya memungkinkan fungsi orkestrator untuk mengabaikan hasil dan melanjutkan. Untuk informasi selengkapnya, lihat dokumentasi Timer.
Pengecualian yang Tidak Tertangani
Jika fungsi orkestrator gagal dengan pengecualian tidak tertangani, detail pengecualian dicatat dan instans selesai dengan Failed status.
Sertakan Properti Pengecualian Kustom untuk FailureDetails (.NET Isolated)
Saat menjalankan alur kerja Tugas Tahan Lama dalam model Terisolasi .NET, kegagalan tugas secara otomatis diserialisasikan ke dalam objek FailureDetails. Secara default, objek ini menyertakan bidang standar seperti:
- ErrorType — nama jenis pengecualian
- Pesan — pesan pengecualian
- StackTrace — pelacakan tumpukan yang diserialisasikan
- InnerFailure – objek FailureDetails bersarang untuk pengecualian yang bersifat internal dan rekursif
Dimulai dengan Microsoft.Azure.Functions.Worker.Extensions.DurableTask v1.9.0, Anda dapat memperluas perilaku ini dengan menerapkan IExceptionPropertiesProvider (ditentukan dalam Paket Microsoft.DurableTask.Worker mulai dari paket v1.16.1). Penyedia ini menentukan jenis pengecualian mana dan properti mana yang harus disertakan dalam kamus FailureDetails.Properties.
Catatan
- Fitur ini hanya tersedia di .NET Isolated . Dukungan untuk Java akan ditambahkan dalam rilis mendatang.
- Pastikan Anda menggunakan Microsoft.Azure.Functions.Worker.Extensions.DurableTask v1.9.0 atau yang lebih baru.
- Pastikan Anda menggunakan Microsoft.DurableTask.Worker v1.16.1 atau yang lebih baru.
Menerapkan Penyedia Properti Pengecualian
Terapkan IExceptionPropertiesProvider kustom untuk mengekstrak dan mengembalikan properti yang dipilih untuk pengecualian yang Anda pedulikan. Kamus yang dikembalikan akan diserialisasi ke dalam bidang Properti 'FailureDetails' saat jenis pengecualian yang cocok dilemparkan.
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
};
}
}
Daftarkan Penyedia
Daftarkan IExceptionPropertiesProvider kustom Anda di host pekerja Terisolasi .NET Anda, biasanya dalam 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();
Setelah terdaftar, pengecualian apa pun yang cocok dengan salah satu jenis yang ditangani akan secara otomatis menyertakan properti yang dikonfigurasi dalam FailureDetails-nya.
Sampel Output DetailKegagalan
Ketika terjadi pengecualian yang cocok dengan konfigurasi penyedia Anda, orkestrasi menerima struktur FailureDetails yang diserialkan seperti ini:
{
"errorType": "TaskFailedException",
"message": "Activity failed with an exception.",
"stackTrace": "...",
"innerFailure": {
"errorType": "ArgumentOutOfRangeException",
"message": "Specified argument was out of range.",
"properties": {
"ParamName": "count",
"ActualValue": 42
}
}
}
Langkah berikutnya