Durable Functions ile Uzun Süreli İş Akışları
Durable Functions, Azure Functions üzerinde durumlu (stateful) orkestrasyonlar yazmayı sağlayan bir uzantıdır. Normal serverless fonksiyonlar durumsuzdur ve 15 dakikalık bir çalışma süresiyle sınırlıdır; Durable Functions ise bu sınırı aşarak günler, haftalar hatta aylar sürebilen iş akışlarını yönetir . Bunu, event sourcing ve replay mekanizmasıyla başarır: her işlem bir olay kaydına yazılır, çökme durumunda iş akışı bu kayıtlardan yeniden oynatılarak kaldığı yerden devam eder .
1. Temel Yapı Taşları: Fonksiyon Rolleri
Durable Functions uygulaması, her biri belirli bir sorumluluğa sahip dört fonksiyon türünden oluşur :
| Rol | Görevi | Tanımı |
|---|---|---|
| Orchestrator | İş akışı mantığını koordine eder; adımları sıralar, dallandırır, sonuçları birleştirir. | Orchestration trigger |
| Activity | Tek bir iş birimini gerçekleştirir: HTTP çağrısı, veritabanı yazımı, model çağrısı. | Activity trigger |
| Entity | Küçük, kalıcı bir durumu yönetir; dağıtık kilit veya durumlu nesne modellemesi. | Entity trigger |
| Client | Orkestrasyonu başlatır, durumunu sorgular, olay gönderir. | Durable client binding |
Kritik Ayrım: Orchestrator yalnızca koordinasyon yapar; dış sistemlerle etkileşim kuran tüm işlemler Activity fonksiyonlarında olur .
2. Determinizm: Orchestrator'ın En Kritik Kuralı
Orchestrator kodu, replay mekanizması nedeniyle deterministik olmak zorundadır. Aynı girdi ve olay geçmişi, her replay'de aynı işlem sırasını üretmelidir .
Orchestrator'da Yasak Olan İşlemler:
-
Doğrudan HTTP, veritabanı, dosya sistemi veya Azure SDK çağrıları
-
DateTime.Now,datetime.now()gibi sistem saati okumaları -
Rastgele sayı üreticileri ve deterministik olmayan UUID API'leri
-
Task.Delay()gibi bloklayan beklemeler; bunun yerineCreateTimerkullanılmalıdır
Deterministik Zaman ve UUID:
csharp
// ❌ Yanlış: Replay'de farklı sonuç üretir var now = DateTime.UtcNow; var id = Guid.NewGuid(); // ✅ Doğru: Replay-güvenli API'ler var now = context.CurrentUtcDateTime; var id = context.NewGuid();
3. Uzun Süreli Beklemeler: Durable Timer
Klasik Task.Delay() bir worker thread'ini bloke eder ve uzun süreli beklemelerde maliyetlidir. Durable Functions'ın CreateTimer API'si ise belirtilen süre boyunca tamamen ücretsizdir; Consumption plan'da beklerken hiçbir ücret alınmaz .
csharp
[Function("OrderWorkflow")]
public async Task RunOrchestrator(
[OrchestrationTrigger] TaskOrchestrationContext context)
{
// 7 gün bekle (ücretsiz)
await context.CreateTimer(
context.CurrentUtcDateTime.AddDays(7),
CancellationToken.None);
await context.CallActivityAsync("SendReminder", "Order-123");
}
Kullanım Senaryoları: Sipariş sonrası takip e-postası, abonelik yenileme hatırlatması, zaman aşımlı onay süreçleri .
4. İnsan Etkileşimi: External Events
Durable Functions, insan onayı bekleyen iş akışları için WaitForExternalEvent API'si sunar. Orkestrasyon, dış bir sinyal gelene kadar süresiz bekleyebilir .
csharp
[Function("ApprovalWorkflow")]
public async Task RunOrchestrator(
[OrchestrationTrigger] TaskOrchestrationContext context)
{
await context.CallActivityAsync("RequestApproval", approvalInfo);
// 72 saat boyunca onay bekle
using var cts = new CancellationTokenSource();
var timeoutTask = context.CreateTimer(
context.CurrentUtcDateTime.AddHours(72), cts.Token);
var approvalTask = context.WaitForExternalEvent<bool>("ApprovalEvent");
var winner = await Task.WhenAny(timeoutTask, approvalTask);
if (winner == approvalTask)
{
cts.Cancel();
if (approvalTask.Result)
await context.CallActivityAsync("ProcessApproval", approvalInfo);
}
else
{
// Zaman aşımı: eskalasyon
await context.CallActivityAsync("Escalate", approvalInfo);
}
}
Olay Gönderme (HTTP API):
bash
curl -d "true" http://localhost:7071/runtime/webhooks/durabletask/instances/{instanceId}/raiseEvent/ApprovalEvent
5. Fan-Out/Fan-In: Paralel İşleme
Durable Functions, birden fazla Activity'yi paralel çalıştırıp sonuçlarını birleştirmeyi kolaylaştırır .
csharp
[Function("BatchProcessing")]
public async Task RunOrchestrator(
[OrchestrationTrigger] TaskOrchestrationContext context)
{
var files = context.GetInput<string[]>();
// Fan-out: Tüm dosyaları paralel işle
var tasks = files.Select(file =>
context.CallActivityAsync<Result>("ProcessFile", file));
// Fan-in: Hepsini bekle
var results = await Task.WhenAll(tasks);
await context.CallActivityAsync("AggregateResults", results);
}
Kullanım Alanları: ETL süreçleri, toplu raporlama, AI ajanlarıyla paralel veri toplama .
6. Sonsuz Orkestrasyonlar: continue-as-new
Sürekli çalışan bir orchestrator (ör. periyodik temizlik), her iterasyonda olay geçmişini biriktirir ve zamanla bellek/performans sorunlarına yol açar. continue-as-new API'si, geçmişi sıfırlayarak aynı instance ID ile orchestrator'ı yeniden başlatır .
csharp
[Function("PeriodicCleanup")]
public async Task RunOrchestrator(
[OrchestrationTrigger] TaskOrchestrationContext context)
{
var input = context.GetInput<CleanupInput>();
// Temizlik işini yap
await context.CallActivityAsync("CleanupOldRecords", input.CutoffDate);
// Bir sonraki iterasyon için timer
await context.CreateTimer(
context.CurrentUtcDateTime.AddHours(1), CancellationToken.None);
// Geçmişi sıfırla ve yeniden başlat
context.ContinueAsNew(new CleanupInput
{
CutoffDate = context.CurrentUtcDateTime.AddDays(-30)
});
}
Önemli Detaylar:
-
Aynı instance ID korunur, ancak yeni bir execution ID oluşturulur .
-
Bekleyen timer'lar ve tamamlanmamış görevler iptal edilir .
-
C# ve Java'da işlenmemiş harici olaylar varsayılan olarak korunur .
7. Sürüm ve Altyapı Notları (2026)
-
Durable Functions v3.x önerilen sürümdür; v2.x'ten geçiş kod değişikliği gerektirmez .
-
Azure Storage SDK güncellenmiştir:
Azure.Data.Tables,Azure.Storage.Blobs,Azure.Storage.Queues. -
Partition Manager V3 varsayılan hale gelmiştir; depolama maliyetini düşürür ve debug'ı kolaylaştırır .
-
Functions Runtime v1 desteği Eylül 2026'da sona ermektedir .
8. Durable Functions vs. Alternatifler
| Özellik | Durable Functions | AWS Step Functions | Temporal |
|---|---|---|---|
| Tanım Yöntemi | Kod (C#, JS, Python) | ASL (JSON/DSL) veya görsel | Kod (Go, Java, TypeScript) |
| Çalışma Yeri | Azure Functions runtime | Bağımsız servis | Kendi worker'ınız |
| Maksimum Süre | Sınırsız (continue-as-new ile) | 1 yıl (Standard) | Sınırsız |
| Görsel Arayüz | Durable Task Scheduler | Step Functions Studio | Temporal UI |
| En Uygun Senaryo | Kod-ağırlıklı, Lambda-içi iş akışları | Servisler arası görsel orkestrasyon | Cross-cloud, karmaşık retry |
Tavsiye: Kod-ağırlıklı ve Lambda-içi iş akışları için Durable Functions; birden fazla AWS servisini kapsayan görsel orkestrasyon için Step Functions; cross-cloud ve daha zengin workflow tooling için Temporal değerlendirilebilir .
9. En İyi Pratikler
| Pratik | Açıklama |
|---|---|
| Orchestrator'ı Deterministik Tutun | Tüm I/O işlemlerini Activity'lere taşıyın . |
| Activity'leri Idempotent Yapın | At-least-once çalışma garantisi nedeniyle tekrarlar olabilir . |
| Timer Kullanın | Task.Delay() yerine CreateTimer; beklerken ücret alınmaz . |
| continue-as-new Kullanın | Sonsuz döngülerde geçmiş birikmesini önleyin . |
| Kritik Bölümler için Entity Kullanın | Paylaşılan durumda yarış koşullarını önlemek için . |
| Hata Yönetimi Yapın | try/catch ve retry politikaları ile dayanıklılık sağlayın . |
Sonuç
Durable Functions, serverless ortamda uzun süreli, durumlu iş akışlarını kod yazarak oluşturmanın en olgun yoludur. Replay tabanlı event sourcing ile çökmelere ve yeniden başlatmalara dayanıklıdır; Durable Timer ile ücretsiz beklemeler, External Events ile insan onayı, Fan-Out/Fan-In ile paralel işleme ve continue-as-new ile sonsuz orkestrasyonlar sağlar. Determinizm kuralına uyulduğu sürece, karmaşık iş akışlarını basit ve sürdürülebilir bir kod tabanıyla yönetebilirsiniz.