fastapi/docs/tr/docs/advanced/events.md

8.5 KiB
Raw Blame History

Lifespan Olayları

Uygulama başlamadan önce çalıştırılması gereken mantığı (kodu) tanımlayabilirsiniz. Bu, bu kodun bir kez, uygulama request almaya başlamadan önce çalıştırılacağı anlamına gelir.

Benzer şekilde, uygulama kapanırken çalıştırılması gereken mantığı (kodu) da tanımlayabilirsiniz. Bu durumda bu kod, muhtemelen çok sayıda request işlendi sonra, bir kez çalıştırılır.

Bu kod, uygulama request almaya başlamadan önce ve requestleri işlemeyi bitirdikten hemen sonra çalıştığı için, uygulamanın tüm lifespanını (birazdan "lifespan" kelimesi önemli olacak 😉) kapsar.

Bu yaklaşım, tüm uygulama boyunca kullanacağınız ve requestler arasında paylaşılan resourceları kurmak ve/veya sonrasında bunları temizlemek için çok faydalıdır. Örneğin bir veritabanı connection poolu ya da paylaşılan bir machine learning modelini yüklemek gibi.

Kullanım Senaryosu

Önce bir kullanım senaryosu örneğiyle başlayalım, sonra bunu bununla nasıl çözeceğimize bakalım.

Requestleri işlemek için kullanmak istediğiniz bazı machine learning modelleriniz olduğunu hayal edelim. 🤖

Aynı modeller requestler 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 fazla data okunması gerektiği için oldukç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 bile modelin 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 ve yavaş olur.

Burada çözeceğimiz şey bu: modeli requestler işlenmeden önce yükleyelim, ama kod yüklenirken değil; yalnızca uygulama request almaya başlamadan hemen önce.

Lifespan

Bu startup ve shutdown mantığını, FastAPI uygulamasının lifespan 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 gibi yield kullanan async bir lifespan() fonksiyonu oluşturuyoruz:

{* ../../docs_src/events/tutorial003_py39.py hl[16,19] *}

Burada, yield öncesinde (sahte) model fonksiyonunu machine learning modellerini içeren dictionarye koyarak, modeli yükleme gibi maliyetli bir startup işlemini simüle ediyoruz. Bu kod, startup sırasında, uygulama request almaya başlamadan önce çalıştırılır.

Ardından yieldden hemen sonra modeli bellekten kaldırıyoruz (unload). Bu kod, uygulama requestleri işlemeyi bitirdikten sonra, shutdowndan hemen önce çalıştırılır. Örneğin memory veya GPU gibi resourceları serbest bırakabilir.

/// tip | İ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 Dependenciese oldukça benzer.

{* ../../docs_src/events/tutorial003_py39.py hl[14:19] *}

Fonksiyonun yieldden önceki kısmı, uygulama başlamadan önce çalışır.

yieldden sonraki kısım ise, uygulama işini bitirdikten sonra ç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.

{* ../../docs_src/events/tutorial003_py39.py hl[1,13] *}

Pythonda context manager, with ifadesi içinde kullanabildiğiniz bir yapıdır. Örneğin open() bir context manager olarak kullanılabilir:

with open("file.txt") as file:
    file.read()

Pythonın güncel sürümlerinde bir de async context manager vardır. Bunu async with ile kullanırsınız:

async with lifespan(app):
    await do_stuff()

Yukarıdaki gibi bir context manager veya async context manager oluşturduğunuzda, yaptığı şey şudur: with bloğuna girmeden önce yieldden önceki kodu çalıştırır, with bloğundan çıktıktan sonra da yieldden sonraki kodu çalıştırır.

Yukarıdaki kod örneğimizde bunu doğrudan kullanmıyoruz; bunun yerine FastAPIye veriyoruz ki o kullansın.

FastAPI uygulamasının lifespan parametresi bir async context manager alır; dolayısıyla oluşturduğumuz yeni lifespan async context managerını buraya geçebiliriz.

{* ../../docs_src/events/tutorial003_py39.py hl[22] *}

Alternatif Events (kullanımdan kaldırıldı)

/// warning | Uyarı

startup ve shutdown işlemlerini yönetmenin önerilen yolu, yukarıda anlatıldığı gibi FastAPI uygulamasının lifespan parametresini kullanmaktır. Bir lifespan parametresi sağlarsanız, startup ve shutdown event handlerları artık çağrılmaz. Ya tamamen lifespan ya da tamamen events; ikisi birden değil.

Muhtemelen bu bölümü atlayabilirsiniz.

///

startup ve shutdown 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 handlerları (fonksiyonları) tanımlayabilirsiniz.

Bu fonksiyonlar async def ile veya normal def ile tanımlanabilir.

startup eventi

Uygulama başlamadan önce çalıştırılacak bir fonksiyon eklemek için, "startup" eventi ile tanımlayın:

{* ../../docs_src/events/tutorial001_py39.py hl[8] *}

Bu durumda startup event handler fonksiyonu, "database" öğesini (sadece bir dict) bazı değerlerle başlatır.

Birden fazla event handler fonksiyonu ekleyebilirsiniz.

Ve tüm startup event handlerları tamamlanmadan uygulamanız request almaya başlamaz.

shutdown eventi

Uygulama kapanırken çalıştırılacak bir fonksiyon eklemek için, "shutdown" eventi ile tanımlayın:

{* ../../docs_src/events/tutorial002_py39.py hl[6] *}

Burada shutdown event handler fonksiyonu, log.txt dosyasına "Application shutdown" satırını yazar.

/// info | Bilgi

open() fonksiyonunda mode="a" "append" anlamına gelir; yani satır, önceki içeriği silmeden dosyada ne varsa onun sonuna eklenir.

///

/// tip | İpucu

Dikkat edin, bu örnekte bir dosyayla etkileşen standart Python open() fonksiyonunu kullanıyoruz.

Dolayısıyla diske yazılmasını beklemeyi gerektiren I/O (input/output) söz konusu.

Ancak open() async ve await kullanmaz.

Bu yüzden event handler fonksiyonunu async def yerine standart def ile tanımlarız.

///

startup ve shutdown birlikte

startup ve shutdown 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ığı gibi lifespan kullanmanız önerilmektedir.

Teknik Detaylar

Meraklı nerdler için küçük bir teknik detay. 🤓

Altta, ASGI teknik spesifikasyonunda bu, Lifespan Protocolün bir parçasıdır ve startup ile shutdown adında eventler tanımlar.

/// info | Bilgi

Starlette lifespan handlerları hakkında daha fazlasını Starlette's Lifespan docs içinde okuyabilirsiniz.

Ayrıca kodunuzun başka bölgelerinde de kullanılabilecek lifespan statei nasıl yöneteceğinizi de kapsar.

///

Alt Uygulamalar

🚨 Unutmayın: Bu lifespan eventleri (startup ve shutdown) yalnızca ana uygulama için çalıştırılır; Alt Uygulamalar - Mounts{.internal-link target=_blank} için çalıştırılmaz.