Dayanıklı İşlev düzenlemeleri kodda uygulanır ve programlama dilinin yerleşik hata işleme özelliklerini kullanabilir. Düzenlemelerinize hata işleme ve telafi eklemek için öğrenmeniz gereken yeni kavramlar yoktur. Ancak, bilmeniz gereken birkaç davranış vardır.
Not
Azure İşlevleri için Node.js programlama modelinin 4. sürümü genel kullanıma sunulmuştur. Yeni v4 modeli, JavaScript ve TypeScript geliştiricileri için daha esnek ve sezgisel bir deneyime sahip olacak şekilde tasarlanmıştır.
Geçiş kılavuzunda v3 ile v4 arasındaki farklar hakkında daha fazla bilgi edinin.
Aşağıdaki kod parçacıklarında JavaScript (PM4), yeni deneyim olan programlama modeli V4'i belirtir.
Etkinlik işlevlerindeki hatalar
Bir etkinlik işlevinde oluşan herhangi bir özel durum orchestrator işlevine geri sıralanır ve olarak FunctionFailedExceptionoluşturulur. Orchestrator işlevinde gereksinimlerinize uygun hata işleme ve telafi kodu yazabilirsiniz.
Örneğin, bir hesaptan diğerine fon aktaran aşağıdaki orchestrator işlevini göz önünde bulundurun:
[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 (Exception)
{
// 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
});
}
}
Not
Önceki C# örnekleri Dayanıklı İşlevler 2.x içindir. Dayanıklı İşlevler 1.x için yerine IDurableOrchestrationContextkullanmanız DurableOrchestrationContext gerekir. Sürümler arasındaki farklar hakkında daha fazla bilgi için Dayanıklı İşlevler sürümleri makalesine bakın.
[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 (Exception)
{
// 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
});
}
}
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,
});
}
});
Varsayılan olarak, PowerShell'deki cmdlet'ler try/catch blokları kullanılarak yakalanabilecek özel durumlar oluşturmaz. Bu davranışı değiştirmek için iki seçeneğiniz vardır:
-ErrorAction Stop gibi Invoke-DurableActivitycmdlet'leri çağırırken bayrağını kullanın.
$ErrorActionPreference Cmdlet'leri çağırmadan önce orchestrator işlevinde tercih değişkenini "Stop" olarak ayarlayın.
PowerShell'de hata işleme hakkında daha fazla bilgi için Try-Catch-Finally PowerShell belgelerine bakın.
@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();
}
}
İlk CreditAccount işlev çağrısı başarısız olursa orchestrator işlevi, fonları kaynak hesaba geri yatırarak telafi eder.
Hatada otomatik yeniden deneme
Etkinlik işlevlerini veya alt düzenleme işlevlerini çağırdığınızda, otomatik bir yeniden deneme ilkesi belirtebilirsiniz. Aşağıdaki örnek, bir işlevi en fazla üç kez çağırmayı dener ve her yeniden deneme arasında 5 saniye bekler:
[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);
// ...
}
Not
Önceki C# örnekleri Dayanıklı İşlevler 2.x içindir. Dayanıklı İşlevler 1.x için yerine IDurableOrchestrationContextkullanmanız DurableOrchestrationContext gerekir. Sürümler arasındaki farklar hakkında daha fazla bilgi için Dayanıklı İşlevler sürümleri makalesine bakın.
@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();
// ...
}
Önceki örnekteki etkinlik işlevi çağrısı, otomatik yeniden deneme ilkesini yapılandırmak için bir parametre alır. Otomatik yeniden deneme ilkesini özelleştirmek için çeşitli seçenekler vardır:
En fazla deneme sayısı: En fazla deneme sayısı. 1 olarak ayarlanırsa yeniden deneme olmaz.
İlk yeniden deneme aralığı: İlk yeniden deneme girişiminden önce bek süre.
Geri alma katsayısı: Geri alma artış oranını belirlemek için kullanılan katsayı. Varsayılan değer 1'tir.
En fazla yeniden deneme aralığı: Yeniden deneme girişimleri arasında bek süre üst sınırı.
Yeniden deneme zaman aşımı: Yeniden denemeler yapmak için harcayacak en fazla süre. Varsayılan davranış, süresiz olarak yeniden denemektir.
Özel yeniden deneme işleyicileri
.NET veya Java kullanırken kodda yeniden deneme işleyicileri uygulama seçeneğiniz de vardır. Bildirim temelli yeniden deneme ilkeleri yeterince açıklayıcı olmadığında bu yararlı olur. Özel yeniden deneme işleyicilerini desteklemeyen diller için döngüleri, özel durum işlemeyi ve yeniden denemeler arasında gecikmeleri eklemek için zamanlayıcıları kullanarak yeniden deneme ilkeleri uygulama seçeneğiniz vardır.
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 şu anda özel yeniden deneme işleyicilerini desteklememektedir. Ancak yine de döngüleri, özel durum işlemeyi ve yeniden denemeler arasında gecikmeleri eklemek için zamanlayıcıları kullanarak düzenleyici işlevinde doğrudan yeniden deneme mantığını uygulama seçeneğiniz vardır.
JavaScript şu anda özel yeniden deneme işleyicilerini desteklememektedir. Ancak yine de döngüleri, özel durum işlemeyi ve yeniden denemeler arasında gecikmeleri eklemek için zamanlayıcıları kullanarak düzenleyici işlevinde doğrudan yeniden deneme mantığını uygulama seçeneğiniz vardır.
Python şu anda özel yeniden deneme işleyicilerini desteklememektedir. Ancak yine de döngüleri, özel durum işlemeyi ve yeniden denemeler arasında gecikmeleri eklemek için zamanlayıcıları kullanarak düzenleyici işlevinde doğrudan yeniden deneme mantığını uygulama seçeneğiniz vardır.
PowerShell şu anda özel yeniden deneme işleyicilerini desteklememektedir. Ancak yine de döngüleri, özel durum işlemeyi ve yeniden denemeler arasında gecikmeleri eklemek için zamanlayıcıları kullanarak düzenleyici işlevinde doğrudan yeniden deneme mantığını uygulama seçeneğiniz vardır.
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...
}
İşlev zaman aşımları
Tamamlanması çok uzun sürüyorsa bir düzenleyici işlevi içindeki işlev çağrısını bırakmak isteyebilirsiniz. Bunu bugün yapmak için uygun yol, aşağıdaki örnekte olduğu gibi "herhangi bir" görev seçici ile dayanıklı bir zamanlayıcı oluşturmaktır:
Önceki C# örnekleri Dayanıklı İşlevler 2.x içindir. Dayanıklı İşlevler 1.x için yerine IDurableOrchestrationContextkullanmanız DurableOrchestrationContext gerekir. Sürümler arasındaki farklar hakkında daha fazla bilgi için Dayanıklı İşlevler sürümleri makalesine bakın.
Bu mekanizma aslında devam eden etkinlik işlevi yürütmesini sonlandırmaz. Bunun yerine, düzenleyici işlevinin sonucu yoksaymasına ve devam etmesine olanak tanır. Daha fazla bilgi için Zamanlayıcılar belgelerine bakın.
İşlenmeyen özel durumlar
Orchestrator işlevi işlenmeyen bir özel durumla başarısız olursa, özel durumun ayrıntıları günlüğe kaydedilir ve örnek bir Failed durumla tamamlar.