Lifespan Olayları¶
🌐 Yapay Zekâ ve İnsanlar Tarafından Çeviri
Bu çeviri, insanlar tarafından yönlendirilen bir yapay zekâ ile oluşturuldu. 🤝
Orijinal anlamın yanlış anlaşılması ya da kulağa doğal gelmeme gibi hatalar içerebilir. 🤖
Yapay zekâ LLM'ini daha iyi yönlendirmemize yardımcı olarak bu çeviriyi iyileştirebilirsiniz.
Uygulamabaşlamadan önce çalıştırılması gereken mantığı (kodu) tanımlayabilirsiniz. Bu, bu kodunbir kez, uygulamarequest almaya başlamadan önce çalıştırılacağı anlamına gelir.
Benzer şekilde, uygulamakapanırken çalıştırılması gereken mantığı (kodu) da tanımlayabilirsiniz. Bu durumda bu kod, muhtemelençok sayıda request işlendisonra,bir kez çalıştırılır.
Bu kod, uygulama request almayabaşlamadan önce ve request’leri işlemeyibitirdikten hemen sonra çalıştığı için, uygulamanın tümlifespan’ını (birazdan "lifespan" kelimesi önemli olacak 😉) kapsar.
Bu yaklaşım, tüm uygulama boyunca kullanacağınız ve request’ler arasındapaylaşılanresource’ları kurmak ve/veya sonrasında bunlarıtemizlemek için çok faydalıdır. Örneğin bir veritabanı connection pool’u ya da paylaşılan bir machine learning modelini yüklemek gibi.
Kullanım Senaryosu¶
Önce birkullanım senaryosu örneğiyle başlayalım, sonra bunu bununla nasıl çözeceğimize bakalım.
Request’leri işlemek için kullanmak istediğiniz bazımachine learning modelleriniz olduğunu hayal edelim. 🤖
Aynı modeller request’ler arasında paylaşılır; yani request başına bir model, kullanıcı başına bir model vb. gibi değil.
Modeli yüklemenin, diskten çok fazladata okunması gerektiği içinoldukça uzun sürebildiğini düşünelim. Dolayısıyla bunu her request için yapmak istemezsiniz.
Modeli modülün/dosyanın en üst seviyesinde yükleyebilirdiniz; ancak bu, basit bir otomatik test çalıştırdığınızda bilemodelin yükleneceği anlamına gelir. Böyle olunca test, kodun bağımsız bir kısmını çalıştırabilmek için önce modelin yüklenmesini beklemek zorunda kalır veyavaş olur.
Burada çözeceğimiz şey bu: modeli request’ler işlenmeden önce yükleyelim, ama kod yüklenirken değil; yalnızca uygulama request almaya başlamadan hemen önce.
Lifespan¶
Bustartup veshutdown mantığını,FastAPI uygulamasınınlifespan parametresi ve bir "context manager" kullanarak tanımlayabilirsiniz (bunun ne olduğunu birazdan göstereceğim).
Önce bir örnekle başlayıp sonra ayrıntılarına bakalım.
Aşağıdaki gibiyield kullanan async birlifespan() fonksiyonu oluşturuyoruz:
fromcontextlibimportasynccontextmanagerfromfastapiimportFastAPIdeffake_answer_to_everything_ml_model(x:float):returnx*42ml_models={}@asynccontextmanagerasyncdeflifespan(app:FastAPI):# Load the ML modelml_models["answer_to_everything"]=fake_answer_to_everything_ml_modelyield# Clean up the ML models and release the resourcesml_models.clear()app=FastAPI(lifespan=lifespan)@app.get("/predict")asyncdefpredict(x:float):result=ml_models["answer_to_everything"](x)return{"result":result}Burada,yield öncesinde (sahte) model fonksiyonunu machine learning modellerini içeren dictionary’e koyarak, modeli yükleme gibi maliyetli birstartup işlemini simüle ediyoruz. Bu kod,startup sırasında, uygulamarequest almaya başlamadan önce çalıştırılır.
Ardındanyield’den hemen sonra modeli bellekten kaldırıyoruz (unload). Bu kod, uygulamarequest’leri işlemeyi bitirdikten sonra,shutdown’dan hemen önce çalıştırılır. Örneğin memory veya GPU gibi resource’ları serbest bırakabilir.
İpucu
shutdown, uygulamayıdurdurduğunuzda gerçekleşir.
Belki yeni bir sürüm başlatmanız gerekiyordur, ya da çalıştırmaktan sıkılmışsınızdır. 🤷
Lifespan fonksiyonu¶
Dikkat edilmesi gereken ilk şey,yield içeren async bir fonksiyon tanımlıyor olmamız. Bu,yield kullanan Dependencies’e oldukça benzer.
fromcontextlibimportasynccontextmanagerfromfastapiimportFastAPIdeffake_answer_to_everything_ml_model(x:float):returnx*42ml_models={}@asynccontextmanagerasyncdeflifespan(app:FastAPI):# Load the ML modelml_models["answer_to_everything"]=fake_answer_to_everything_ml_modelyield# Clean up the ML models and release the resourcesml_models.clear()app=FastAPI(lifespan=lifespan)@app.get("/predict")asyncdefpredict(x:float):result=ml_models["answer_to_everything"](x)return{"result":result}Fonksiyonunyield’den önceki kısmı, uygulama başlamadanönce çalışır.
yield’den sonraki kısım ise, uygulama işini bitirdiktensonra çalışır.
Async Context Manager¶
Bakarsanız, fonksiyon@asynccontextmanager ile dekore edilmiş.
Bu da fonksiyonu "async context manager" denen şeye dönüştürür.
fromcontextlibimportasynccontextmanagerfromfastapiimportFastAPIdeffake_answer_to_everything_ml_model(x:float):returnx*42ml_models={}@asynccontextmanagerasyncdeflifespan(app:FastAPI):# Load the ML modelml_models["answer_to_everything"]=fake_answer_to_everything_ml_modelyield# Clean up the ML models and release the resourcesml_models.clear()app=FastAPI(lifespan=lifespan)@app.get("/predict")asyncdefpredict(x:float):result=ml_models["answer_to_everything"](x)return{"result":result}Python’dacontext manager,with ifadesi içinde kullanabildiğiniz bir yapıdır. Örneğinopen() bir context manager olarak kullanılabilir:
withopen("file.txt")asfile:file.read()Python’ın güncel sürümlerinde bir deasync context manager vardır. Bunuasync with ile kullanırsınız:
asyncwithlifespan(app):awaitdo_stuff()Yukarıdaki gibi bir context manager veya async context manager oluşturduğunuzda, yaptığı şey şudur:with bloğuna girmeden önceyield’den önceki kodu çalıştırır,with bloğundan çıktıktan sonra dayield’den sonraki kodu çalıştırır.
Yukarıdaki kod örneğimizde bunu doğrudan kullanmıyoruz; bunun yerine FastAPI’ye veriyoruz ki o kullansın.
FastAPI uygulamasınınlifespan parametresi birasync context manager alır; dolayısıyla oluşturduğumuz yenilifespan async context manager’ını buraya geçebiliriz.
fromcontextlibimportasynccontextmanagerfromfastapiimportFastAPIdeffake_answer_to_everything_ml_model(x:float):returnx*42ml_models={}@asynccontextmanagerasyncdeflifespan(app:FastAPI):# Load the ML modelml_models["answer_to_everything"]=fake_answer_to_everything_ml_modelyield# Clean up the ML models and release the resourcesml_models.clear()app=FastAPI(lifespan=lifespan)@app.get("/predict")asyncdefpredict(x:float):result=ml_models["answer_to_everything"](x)return{"result":result}Alternatif Events (kullanımdan kaldırıldı)¶
Uyarı
startup veshutdown işlemlerini yönetmenin önerilen yolu, yukarıda anlatıldığı gibiFastAPI uygulamasınınlifespan parametresini kullanmaktır. Birlifespan parametresi sağlarsanız,startup veshutdown event handler’ları artık çağrılmaz. Ya tamamenlifespan ya da tamamen events; ikisi birden değil.
Muhtemelen bu bölümü atlayabilirsiniz.
startup veshutdown sırasında çalıştırılacak bu mantığı tanımlamanın alternatif bir yolu daha vardır.
Uygulama başlamadan önce veya uygulama kapanırken çalıştırılması gereken event handler’ları (fonksiyonları) tanımlayabilirsiniz.
Bu fonksiyonlarasync def ile veya normaldef ile tanımlanabilir.
startup eventi¶
Uygulama başlamadan önce çalıştırılacak bir fonksiyon eklemek için,"startup" event’i ile tanımlayın:
fromfastapiimportFastAPIapp=FastAPI()items={}@app.on_event("startup")asyncdefstartup_event():items["foo"]={"name":"Fighters"}items["bar"]={"name":"Tenders"}@app.get("/items/{item_id}")asyncdefread_items(item_id:str):returnitems[item_id]Bu durumdastartup event handler fonksiyonu, "database" öğesini (sadece birdict) bazı değerlerle başlatır.
Birden fazla event handler fonksiyonu ekleyebilirsiniz.
Ve tümstartup event handler’ları tamamlanmadan uygulamanız request almaya başlamaz.
shutdown eventi¶
Uygulama kapanırken çalıştırılacak bir fonksiyon eklemek için,"shutdown" event’i ile tanımlayın:
fromfastapiimportFastAPIapp=FastAPI()@app.on_event("shutdown")defshutdown_event():withopen("log.txt",mode="a")aslog:log.write("Application shutdown")@app.get("/items/")asyncdefread_items():return[{"name":"Foo"}]Buradashutdown event handler fonksiyonu,log.txt dosyasına"Application shutdown" satırını yazar.
Bilgi
open() fonksiyonundamode="a" "append" anlamına gelir; yani satır, önceki içeriği silmeden dosyada ne varsa onun sonuna eklenir.
İpucu
Dikkat edin, bu örnekte bir dosyayla etkileşen standart Pythonopen() fonksiyonunu kullanıyoruz.
Dolayısıyla disk’e yazılmasını beklemeyi gerektiren I/O (input/output) söz konusu.
Ancakopen()async veawait kullanmaz.
Bu yüzden event handler fonksiyonunuasync def yerine standartdef ile tanımlarız.
startup veshutdown birlikte¶
startup veshutdown mantığınızın birbiriyle bağlantılı olma ihtimali yüksektir; bir şeyi başlatıp sonra bitirmek, bir resource edinip sonra serbest bırakmak vb. isteyebilirsiniz.
Bunu, ortak mantık veya değişken paylaşmayan ayrı fonksiyonlarda yapmak daha zordur; çünkü değerleri global değişkenlerde tutmanız veya benzer numaralar yapmanız gerekir.
Bu nedenle artık bunun yerine, yukarıda açıklandığı gibilifespan kullanmanız önerilmektedir.
Teknik Detaylar¶
Meraklı nerd’ler için küçük bir teknik detay. 🤓
Altta, ASGI teknik spesifikasyonunda bu,Lifespan Protokolü’nün bir parçasıdır vestartup ileshutdown adında event’ler tanımlar.
Bilgi
Starlettelifespan handler’ları hakkında daha fazlasınıStarlette Lifespan dokümanları içinde okuyabilirsiniz.
Ayrıca kodunuzun başka bölgelerinde de kullanılabilecek lifespan state’i nasıl yöneteceğinizi de kapsar.
Alt Uygulamalar¶
🚨 Unutmayın: Bu lifespan event’leri (startup veshutdown) yalnızca ana uygulama için çalıştırılır;Alt Uygulamalar - Mounts için çalıştırılmaz.







