lilydocs
HTTP APIWebSocketConsumer
Temeller3 dk okuma

Bağımlılık enjeksiyonu

Singleton worker ile delivery kapsamındaki Scoped servisleri doğru ömürlerle birleştirin.

Consumer'ın DI container'ı iş servislerini worker'lardan ayırır. Handler'ın görevi mesajı alıp uygun servisi çağırmak olduğunda aynı iş mantığını HTTP API, WebSocket veya farklı mesaj sözleşmelerinde tekrar kullanabilirsiniz.

Bağımlılıklar ve public giriş#

İlk uygulamanın manifesti yeterlidir. Injectable ve ServiceTrait, lilyrs::consumer altında; handler'ın Service<T> extractor'ı lilyrs::queue altındadır. Consumer için derive, registry veya ayrı injection feature'ını eklemeniz gerekmez.

Ömürleri delivery etrafında düşünün#

Ömür Oluşturulma ve paylaşım Uygun kullanım
Singleton Bir application container içinde paylaşılır Configuration, ortak policy, bağlantı pool'u
Scoped Aynı delivery scope içindeki çözümler paylaşır Mesaj işleme servisi ve delivery'ye ait durum
Transient Her çözümlemede yeni instance Paylaşılması gerekmeyen kısa iş nesnesi

Singleton worker çok sayıda delivery tarafından çağrılabilir. Scoped servisi bu worker'ın field'ında tutmak delivery ömrünü aşar. Bunun yerine Service<T> handler parametresi kullanın. Aynı delivery içinde middleware, guard veya extractor aynı Scoped servisi çözüyorsa aynı instance'a erişir.

Scoped iş servisiyle tam örnek#

Aşağıdaki di.rs dosyası, ilk uygulamanın src/main.rs dosyasının alternatifidir. Aynı Cargo manifesti, lily.toml ve publisher ile çalışır:

di.rs
use lilyrs::{
    consumer::{Consumer, ConsumerError, Injectable, ServiceTrait},
    queue::{DeliveryCancellation, EventId, Json, QueueHandlerError, Service, queue, queue_service},
};
use serde::Deserialize;
#[derive(Default, Injectable)]
#[service(lifetime = "Scoped")]
struct OrderService;
impl ServiceTrait for OrderService {}
impl OrderService {
    async fn process(&self, id: String) -> Result<(), QueueHandlerError> {
        if id.is_empty() { return Err(QueueHandlerError::permanent("ORDER_ID_REQUIRED")); }
        Ok(())
    }
}
#[derive(Deserialize)]
struct OrderCreated { order_id: String }
#[derive(Default, Injectable)]
#[service(lifetime = "Singleton")]
struct OrderWorker;
impl ServiceTrait for OrderWorker {}
#[queue_service]
impl OrderWorker {
    #[queue("orders.created", version = 1, content = "json")]
    async fn created(&self, orders: Service<OrderService>, _event_id: EventId,
        _cancellation: DeliveryCancellation, Json(event): Json<OrderCreated>) -> Result<(), QueueHandlerError> {
        orders.process(event.order_id).await
    }
}
#[tokio::main]
async fn main() -> Result<(), ConsumerError> { Consumer::run().await }

OrderService, boş kimliği kalıcı hata olarak reddeder. Service<OrderService> aktif scope üzerinden çözülür. Örnekte _event_id ve _cancellation parametreleri metadata/sinyal erişimini gösterir; bunları almak tek başına idempotency veya cancellation-safe bir dış işlem sağlamaz.

Constructor injection ve interface#

Rust
use std::sync::Arc;
use lilyrs::consumer::{Injectable, ServiceTrait};

#[derive(Default, Injectable)]
#[service(lifetime = "Singleton")]
struct OrderPolicy;
impl ServiceTrait for OrderPolicy {}

#[derive(Injectable)]
#[service(lifetime = "Scoped")]
struct OrderApplication {
    #[inject]
    policy: Arc<OrderPolicy>,
}
impl ServiceTrait for OrderApplication {}

Bu parça, Scoped servisin Singleton policy tutmasını gösterir. #[inject] field'ı Arc<T> veya Arc<dyn Trait> olmalıdır. Named field'ların hepsi inject ediliyorsa Default gerekmez; inject edilmeyen runtime field'ları için derive'ın Default gereksinimini karşılayın.

Interface kayıtları da aynı container'dadır. Bir interface uygulamanın DI kaydında bağlanmışsa handler Service<dyn OrderOperations> çözebilir. Yalnız Rust trait'ini tanımlamak bir DI binding oluşturmaz. Worker owner'ı da kayıtlı bir servis olmalıdır; zorunlu Singleton kuralı yoktur, Scoped worker aktif delivery scope içinde çözülür.

Başlatma, disposal ve dış container#

ServiceTrait::initialize(&mut self) ve dispose(&self) DI lifecycle hook'larıdır. Handler bunları elle çağırmaz. Lily, delivery scope'unu normal pipeline sonrasında cleanup yoluna taşır; queue runtime kapanışı kanıtlanmadan framework-owned application container'ın disposal'ını başarılı saymaz.

.container(Arc<ApplicationContainer>) ile verilen container çağırana aittir. Consumer queue runtime'ını kapatmayı sürdürür; dış container'ı kapatma kararı üst owner'dadır. Aktif Consumer kullanıcıları varken container'ı kapatmayın ve bir hata sonucunu otomatik drain kanıtı kabul etmeyin. Managed Consumer bu sınırı raporlarla yönetir.

Bu sayfanın kaynakları v0.1.0

Anlatım, incelenen framework commit’ine dayanır.

HIZLI BAŞLANGIÇ
Dokümantasyon
Kaynak kod