Lambda Durable Functions vs Step Functions: Orkestratör Ne Zaman Kodunuza Ait?
Lambda durable functions orkestratörü TypeScript kodunuza taşır. Tüm iş akışı sizinse onları seçin; Step Functions'ı görsel, ekipler arası state machine'ler için saklayın.
Problem
AWS Lambda üzerindeki çok adımlı bir iş akışı uzun süredir kimsenin sevmediği bir ayrımı dayatıyordu: orkestrasyon mantığı bir Amazon States Language (ASL) state machine içinde, çağırdığı fonksiyonların iş mantığı ise başka yerde durur. Altı adımlı bir sipariş saga’sı bir deploy biriminde JSON state tanımına, başka bir deploy biriminde TypeScript’e dönüşür; tek satırlık bir retry-policy değişikliği, koordine ettiği kodu değil bir state machine’i düzenlemek demektir. Genel kullanıma açılan Lambda durable functions ile bu ayrım artık zorunlu değil: duruşum şu ki, tüm iş akışı baştan sona sizinse orkestratörü durable bir Lambda içinde sıradan TypeScript olarak yazmalı, Step Functions’ı ise görsel, ekipler arası veya ödünç alınmış orkestrasyon için saklamalısınız. Bunun bedeli determinizm vergisidir.
Ayrımı kaldırmaya değmesinin nedeni, iki yarının birbirinden uzaklaşmasıdır. İncelemeciler iş akışını okumak için ASL JSON, bir Lambda ve bir SQS kuyruğu arasında zıplar. Testler state-machine mantığını kod içinde tekrarlar, çünkü state machine kod olarak unit-test edilemez. Durable bir fonksiyon bunu yukarıdan aşağı okuyabileceğiniz tek bir anlatıya indirir. Yine de değiş tokuş gerçek: model yalnızca replay’i yöneten determinizm kısıtını kabul ederseniz ayakta kalır ve işin çoğu tam da o kısıtın etrafında toplanır.
Çalışma Modeli
Durable bir fonksiyon, uzun ömürlü, checkpoint’lenen bir durable execution çalıştıran sıradan bir Lambda’dır. AWS, bunun bir yıla kadar çalışabileceğini belirtir. İçeride bir checkpoint-ve-replay mekanizması kullanır: fonksiyon bir kesinti ya da duraklamanın ardından devam ettiğinde kodunuz baştan çalışır, ama tamamlanmış işlemleri atlar ve onları yeniden çalıştırmak yerine kaydedilmiş sonuçlarını replay eder.
Modeli iki durable işlem taşır:
- Step’ler iş mantığınıza otomatik retry ve checkpoint ekler. Her
context.step()çağrısı yürütmeden önce ve sonra bir checkpoint oluşturur; bir step tamamlandığında replay onu yeniden çalıştırmak yerine kaydedilmiş sonucunu kullanır. Yan etkiler (SDK çağrıları, yazma işlemleri, gönderimler) buraya aittir. - Wait’ler yürütmeyi bir süreliğine duraklatır. Fonksiyon sonlanır ve compute ücreti olmadan askıya alınır, sonra replay yoluyla devam eder. Bu, human-in-the-loop onayları, polling ve timer’lar için kullanılan primitif’tir. Bir callback primitif’i ise dış onayları kapsar: yürütme, dışarıdaki bir sistem sonuç gönderene kadar askıda kalır.
TypeScript’te handler’ı withDurableExecution ile sararsınız; bu, fonksiyonunuza step() ve wait() sunan bir DurableContext verir. Python karşıtlık için not edilmeye değer farklı bir şekil alır: @durable_execution ve @durable_step dekoratörlerini kullanır ve Python SDK’si senkrondur, await yoktur. Bu yazının üzerine kurulduğu yol TypeScript’tir.
Maliyet tarafında AWS, wait durumu için açıktır: on-demand fonksiyonlarda bir wait sırasında fonksiyon compute ücreti almadan askıya alınır, dolayısıyla saatlerce ya da günlerce bekleyen bir iş akışı yalnızca gerçek işleme süresi için ödeme yapar, boşta bekleme için değil. Yine de bekleme tümüyle bedava değildir. Her checkpoint bir veri-yazma ücreti taşır ve saklanan state, yürütme onu tuttuğu sürece bir saklama (retention) ücreti üretir. Yürütme rolünün lambda:CheckpointDurableExecution ve lambda:GetDurableExecutionState izinlerine ihtiyacı vardır.
Not: Durable functions Aralık 2025’te genel kullanıma açıldı ve özellik hâlâ bölgeler ve runtime’lar arasında genişliyor. Buna bağlanmadan önce runtime sürümlerini ve bölge erişilebilirliğini güncel AWS sayfalarından doğrulayın.
Determinizm vergisi
Replay, handler’ı baştan yeniden çalıştırır. İkinci çalıştırmada farklı bir değer üreten her şey, yürütmenin kaldığı yerden devam ettiği yanılsamasını bozar. AWS kuralı net koyar: bir fonksiyon devam ettiğinde Lambda kodunuzu baştan çalıştırır, tamamlanmış step’ler yeniden çalışmaz ve “İşte bu yüzden kodunuz deterministik olmalıdır.”
Bu tek kısıt, asıl kod yazarken karşılaştığınız kuralları doğurur:
- Her yan etki bir step’in içinde durur. Handler gövdesindeki doğrudan bir SDK çağrısı her replay’de yeniden çalışır. Bu da çift tahsilat ve çift e-posta demektir. Onu
context.step()ile sarmak sonucu checkpoint’ler, böylece replay çağrıyı yeniden tetiklemek yerine kaydı okur. - Her deterministik olmayan değer bir step’in içinde durur.
Date.now(),Math.random()vecrypto.randomUUID()replay’ler arasında kayar. Belgelenen çözüm özel bir yardımcı değildir; çağrıyı bir step ile sarmaktır, böylece değer bir kez hesaplanır, checkpoint’lenir ve kayıttan replay edilir. Sonucu başka herhangi bir step çıktısı gibi ele alın. - Step kimliği sözleşmenin bir parçasıdır. AWS best practice’leri uyarır: “Step’leri yeniden adlandırmayın ya da davranışlarını replay’i bozacak şekilde değiştirmeyin.” Akış ortasında yapılan bir yeniden adlandırma checkpoint’i sahipsiz bırakır. Yürütmeleri bir sürüme ya da alias’a sabitleyin ve yeni kodun, eski kodun checkpoint’lediği state’i hâlâ okuyabildiğinden emin olun.
Uygulamada handler gövdesi saf orkestrasyona dönüşür: step sonuçları üzerinde kontrol akışı, başka bir şey değil. Bu, Azure Durable Functions ve Temporal’ın orkestratör koduna dayattığı aynı disiplindir; daha önce replay-güvenli orkestratörler yazdıysanız model doğrudan oturur.
Kodda saga vs ASL
Bu değiş tokuşu görmenin en net yolu, aynı sipariş saga’sını her iki şekilde yazmaktır. Önce orkestratörün sıradan kontrol akışı olduğu durable fonksiyon:
import { DurableContext, withDurableExecution } from "@aws/durable-execution-sdk-js";
export const handler = withDurableExecution(
async (event: OrderEvent, context: DurableContext) => {
const payment = await context.step("charge-payment", () =>
chargePayment(event.orderId, event.amount)
);
try {
const shipment = await context.step("reserve-inventory", () =>
reserveInventory(event.orderId, event.items)
);
await context.step("confirm-order", () => confirmOrder(event.orderId));
return { status: "confirmed", shipment };
} catch (err) {
// telafi işlemi: saga rollback'i sıradan bir catch bloğunda
await context.step("refund-payment", () =>
refundPayment(payment.chargeId)
);
throw err;
}
}
);
Rollback sade bir catch. Retry’ler bir step seçeneği. Tüm saga yukarıdan aşağı tek bir fonksiyon olarak okunur ve step gövdelerini stub’layarak unit-test edebilirsiniz. Aynı saga, ASL olarak ise bir veri yapısıdır:
{
"Comment": "Siparis saga (ornek ASL)",
"StartAt": "ChargePayment",
"States": {
"ChargePayment": { "Type": "Task", "Resource": "arn:...:chargePayment", "Next": "ReserveInventory" },
"ReserveInventory": {
"Type": "Task", "Resource": "arn:...:reserveInventory",
"Catch": [{ "ErrorEquals": ["States.ALL"], "Next": "RefundPayment" }],
"Next": "ConfirmOrder"
},
"ConfirmOrder": { "Type": "Task", "Resource": "arn:...:confirmOrder", "End": true },
"RefundPayment": { "Type": "Task", "Resource": "arn:...:refundPayment", "Next": "Failed" },
"Failed": { "Type": "Fail" }
}
}
Telafi yolu bir Catch kuralıdır. Konsoldaki hikâye güçlüdür: herkes grafiği açıp saga’nın state’ten state’e geçişini izleyebilir. Kod incelemesi ve unit testteki hikâye ise daha zayıftır, çünkü mantık, test paketinin doğrudan çalıştıramayacağı bir JSON’dur. Tüm değiş tokuş bu iki dosyada toplanır. Durable fonksiyon, iş akışına sahip olup onu değiştiren geliştirici için optimize eder; ASL ise onu görmesi gereken okuyucu için optimize eder.
Sahip olduğum bir iş akışında ilk uzanacağım şekil budur. Kendi kodum için dürüst çekince: bugün çalıştırdığım bir saga, bir idempotency penceresi için bir Date.now() ve ilk task’tan önce doğrudan bir SDK yazma çağrısı kullanıyor; replay’in güvenli olması için ikisinin de step’lerin içine taşınması gerekir. Determinizm vergisi soyut değildir; yan etkiler konusunda dikkatsiz davrandığınız yere tam isabet eder.
Önerilen varsayılan
Tek ekibin, tek bounded context’in ve kodunuzla birlikte değişen mantığın olduğu, baştan sona sizin olan bir iş akışı için orkestratörü TypeScript’te durable bir Lambda olarak yazın. Tek deploy birimi, sıradan kontrol akışı, test edebileceğiniz kod ve bir incelemecinin tek anlatı olarak okuyabileceği bir iş akışı elde edersiniz. Step Functions o zaman başlangıç noktası değil, belirli durumlar için bir override hâline gelir.
Bu varsayılanın arkasındaki değiş tokuşu doğrudan söylemeye değer. Durable functions size orkestratör-in-code kazandırır, bedeli ise determinizm vergisi ve özelliğin yeniliğidir: Step Functions’tan daha genç ve daha az kanıtlanmıştır, Java SDK’si ancak Nisan 2026’da genel kullanıma açıldı, dolayısıyla bugün olgun yollar JS/TS ve Python’dur. Çalışan bir Step Functions makinesi olan, riskten kaçınan bir ekibin, durable şekil daha temiz okunacak olsa bile onu yerinde bırakmak için meşru bir gerekçesi vardır. Daha yeni olmak, daha az bilinen hata modu demektir ve bu, karara giren gerçek bir girdidir, savuşturulacak bir kusur değil.
Aşağıdaki karar ağacı durable-fonksiyon varsayılanında köklenir; her dal Step Functions’a doğru bir override adlandırır.
Step Functions’ın hâlâ kazandığı durumlar
AWS’in kendi karar sayfası sınırı çizer ve bu tezle örtüşür. Step Functions’ı şu durumlarda kullanmanızı söyler: ekipler arası görünürlük için görsel bir iş akışı temsiline ihtiyaç duyduğunuzda, birden çok AWS servisini orkestre edip özel SDK kodu olmadan native entegrasyonlar istediğinizde, yama ya da runtime güncellemesi olmayan sıfır-bakım altyapı gerektirdiğinizde ve teknik olmayan paydaşların iş akışı mantığını anlayıp doğrulaması gerektiğinde. AWS, durable functions’ı “Lambda içinde uygulama geliştirme için optimize edilmiş”, Step Functions’ı ise “AWS servisleri arasında iş akışı orkestrasyonu için inşa edilmiş” olarak çerçeveler. Override durumları bu çerçeveden çıkar:
- Mühendis olmayanlar da hedef kitlenin parçası. Ops, uyum ya da ürün ekipleri iş akışı grafiğini konsoldan okuduğunda, kod onların arayüzü değildir. AWS, “teknik olmayan paydaşların iş akışı mantığını anlayıp doğrulaması gerekiyor”u bir Step Functions tetikleyicisi olarak listeler ve durable bir fonksiyon bu görünümü sunamaz.
- İş akışı servis yapıştırması, mantık değil. Step Functions, 220’den fazla AWS servisi ve 16.000 API üzerinde özel SDK kodu olmadan native entegrasyonlar sunar. İş akışı dallanan mantıktan çok servisten servise kablolama olduğunda, bu doğrudan entegrasyonlar, step’ler içine elle yazılmış SDK çağrılarına karşı kazanır.
- Runtime’dan bağımsız, sıfır-bakım altyapı istiyorsunuz. AWS, Step Functions’ı tam yönetilen ve runtime’dan bağımsız, yama ya da runtime güncellemesi olmayan olarak çerçeveler. Durable bir fonksiyon Lambda ortamı içinde çalışır ve Lambda’nın runtime yaşam döngüsünü devralır.
- State machine ekipler arası bir sözleşmedir. Bir iş akışı ekipleri kapsadığında, state machine her tarafın üzerinde uzlaştığı ortak, görsel artefakttır. AWS bunu ekipler arası görünürlük olarak çerçeveler ve o görünürlük asıl meseledir.
Buradaki en güçlü kanıt, AWS’in aynı varsayılanı onaylamasıdır. Migrasyon rehberi şöyle der: “Lambda-merkezli iş akışları için durable functions ile başlayın. Çok-servisli orkestrasyona ya da görsel iş akışı tasarımına ihtiyaç duyduğunuzda Step Functions ekleyin.” Mevcut kullanıcılar için ekler: yerleşik servisler-arası iş akışları için Step Functions’ı koruyun, güvenilirlik gerektiren yeni Lambda uygulama mantığı için durable functions’ı değerlendirin. Bu, satıcının, sahip olduğunuz iş akışları için durable-önce’yi önermesidir; tam da bu yazının aldığı duruş.
Sık yapılan hatalar
- Yan etkiyi step yerine handler gövdesine koymak. Her replay’de yeniden çalışır: çift tahsilat, çift e-posta. Her etkiyi bir step ile sarın.
- Deterministik olmayan değeri handler gövdesine koymak.
Date.now(), rastgelelik ve UUID’ler replay’ler arasında kayar ve devam eden state’i bozar. Onları bircontext.step()içinde üretin, böylece değer bir kez checkpoint’lenir ve replay edilir. - Step’i deploy’lar arasında yeniden adlandırmak ya da davranışını değiştirmek. Akış ortasında yeniden adlandırma checkpoint’i sahipsiz bırakır. Yürütmeleri bir sürüme ya da alias’a sabitleyin ve step kimliğini sabit tutun.
- Wait’i bir busy-loop gibi kullanmak. Uzun duraklamalar için, CPU’yu sürekli faturalandıran bir polling döngüsü yerine, compute ücreti olmadan askıya alan bir durable wait kullanın.
- Tek kısa bir Lambda yeterken durable fonksiyona uzanmak. Tek seferlik bir fonksiyonda orkestrasyon yükü israftır; durable functions çok adımlı, uzun ömürlü ya da çökmeye duyarlı akışlarda hak ettiğini verir.
- Bir ASL makinesini koda taşıyıp görseli sessizce düşürmek. Konsol grafiğine bağımlı paydaşlar arayüzlerini kaybeder. Migrasyon yalnızca bir kod değişikliği değil, bir iletişim değişikliğidir.
Bu iş akışlarının uyguladığı daha geniş saga modeli için dağıtık işlemler için saga deseni yazısına bakın. Yerleşik orkestratörün tam modeli için Step Functions derinlemesine yazısı ASL’yi, Standard vs Express’i ve doğrudan entegrasyonları kapsar. Tek bir Lambda’ya ne kadar mantık ait olduğu sorusu Lambda fonksiyon granülerliği ile bağlantılıdır ve özellikle agentic çok adımlı akışlar için production’da Bedrock AgentCore ilgili bir orkestrasyon yüzeyini ele alır.
Kapanış
İş akışı baştan sona sizinse durable bir Lambda’yı varsayılan alın: tek ekip, tek bounded context, kodunuzla birlikte hareket eden mantık. Orkestratör tek deploy biriminde sıradan TypeScript’e dönüşür ve bunun bedelini determinizm vergisiyle ödersiniz; her yan etki ve her deterministik olmayan değer bir step’in içine itilir. Sınır tersine döndüğünde Step Functions’a uzanın: mühendis olmayan biri görsele ihtiyaç duyuyorsa, iş akışı çoğunlukla servisler-arası yapıştırmaysa ya da state machine ekipler arasında paylaşılan bir sözleşmeyse. Bir sonraki somut adım, sahip olduğunuz bir iş akışı seçmek, handler gövdesine dönüşecek kısmını Date.now() ve doğrudan SDK çağrıları açısından denetlemek ve determinizm vergisinin aslında ne kadarına dokunacağını görmektir.
Kaynaklar
- Lambda durable functions (AWS Lambda Developer Guide) - Mekanizmanın birincil kaynağı: checkpoint ve replay, step vs wait, bir yıllık maksimum ve kullanım durumu listesi. Yayından önce güncelliği doğrulayın; özellik yedi aydan genç.
- Durable functions or Step Functions (AWS Lambda Developer Guide) - Resmi karar sayfası: her birini ne zaman kullanacağınız, özellik karşılaştırma tablosu ve sınır bölümünde alıntılanan migrasyon rehberi.
- Lambda durable functions oluşturma, başlangıç (AWS Lambda Developer Guide) - Doğrulanmış API yüzeyi ve “kodunuz deterministik olmalıdır” ifadesi.
- TypeScript SDK referansı (AWS Durable Execution SDK) -
@aws/durable-execution-sdk-jsimport’unu,withDurableExecutionsarmalayıcısını vecontext.step()ilecontext.wait()imzalarını doğrular. - Lambda durable functions için best practice’ler (AWS Lambda Developer Guide) - Step-kimliği kuralının kaynağı: step’leri yeniden adlandırmayın ya da replay’i bozacak şekilde davranışını değiştirmeyin; sürüm ve alias kullanın.
- AWS Durable Execution SDK Developer Guide - Callback’leri, parallel ve map işlemlerini, child context’leri ve açık kaynak SDK depolarını listeleyen SDK açılış sayfası.
- AWS Lambda durable functions ile çok adımlı uygulamalar ve AI iş akışları kurun (AWS News Blog) - Tam uçtan uca sipariş işleme örneği ve iki-primitif çerçevesiyle lansman yazısı.
- AWS Lambda durable functions duyurusu (What’s New) - Aralık 2025 genel kullanım duyurusu, ilk bölge ve runtime desteğiyle.
- AWS Lambda Durable Execution SDK for Java GA (What’s New) - Olgunluk notunu temellendirir: JS/TS ve Python olgun yollar, Java SDK en yeni.
- aws-durable-execution-sdk-js (GitHub) - Açık kaynak JS/TS SDK’si; import yolu ve güncel sürüm için yetkili kaynak.
- AWS Step Functions Developer Guide - Yerleşik orkestratör: ASL, Standard vs Express ve doğrudan servis entegrasyonları.
- Amazon States Language spesifikasyonu - Karşılaştırmanın saga-as-data tarafı için ASL referansı.
- AWS Lambda Pricing - Fiyatlandırma iddialarını temellendirir: on-demand fonksiyonlarda wait sırasında compute ücreti yok, ayrıca checkpoint başına veri-yazma ve state saklama ücretleri var.
İlgili yazılar
Mimari ağırlığını runtime'ın init-amortismanına göre seç: single-purpose Lambda'da yalın handler, Lambdalith'te orta, tam OOP/DI yalnızca uzun ömürlü runtime'da.
AWS Lambda fonksiyonlarını nasıl bölmeli: varsayılan single-purpose, single-domain Lambdalith'i hak edilmiş istisna gör, kararı veren platform güçlerini tanı.
DI container'lar, monolitik SDK'lar, god-handler'lar, modül üstü secret çağrıları ve ağır ORM'ler - soğuk başlatmada bedeli ve yerine geçen fonksiyonel yapı.
Bun ve Deno'yu AWS Lambda'da custom runtime ile çalıştırma: gerçek performans benchmark'ları, maliyet analizi ve production deployment pattern'leri.
Effect'i adım adım öğrenmek ve AWS Lambda ile entegre etmek için pratik bir rehber: gerçek kod örnekleri, yaygın hatalar ve üretim desenleri.