Aracılığıyla paylaş


Olaylara abone olma

İpucu

Bu içerik, .NET Docs'ta veya çevrimdışı olarak okunabilen ücretsiz indirilebilir bir PDF olarak sağlanan Kapsayıcılı .NET Uygulamaları için .NET Mikro Hizmet Mimarisi e-Kitabı'ndan bir alıntıdır.

.NET Microservices Architecture for Containerized .NET Applications eBook cover thumbnail.

Olay veri yolunu kullanmanın ilk adımı, mikro hizmetleri almak istedikleri olaylara abone olmaktır. Bu işlev alıcı mikro hizmetlerinde yapılmalıdır.

Aşağıdaki basit kod, her alıcı mikro hizmetinin hizmeti başlatırken ( Startup yani sınıfında) ihtiyaç duyduğu olaylara abone olması için uygulaması gerekenleri gösterir. Bu durumda mikro basket-api hizmetin ve OrderStartedIntegrationEvent iletilerine ProductPriceChangedIntegrationEvent abone olması gerekir.

Örneğin, olaya abone ProductPriceChangedIntegrationEvent olurken, sepet mikro hizmetini ürün fiyatındaki değişiklikleri fark eder ve söz konusu ürün kullanıcının sepetindeyse kullanıcıyı değişiklik hakkında uyarmasına olanak tanır.

var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>();

eventBus.Subscribe<ProductPriceChangedIntegrationEvent,
                   ProductPriceChangedIntegrationEventHandler>();

eventBus.Subscribe<OrderStartedIntegrationEvent,
                   OrderStartedIntegrationEventHandler>();

Bu kod çalıştırıldıktan sonra abone mikro hizmeti RabbitMQ kanallarını dinler. ProductPriceChangedIntegrationEvent türünde bir ileti geldiğinde, kod ona geçirilen olay işleyicisini çağırır ve olayı işler.

Olay veri yolu aracılığıyla olayları yayımlama

Son olarak, ileti gönderen (kaynak mikro hizmeti) tümleştirme olaylarını aşağıdaki örneğe benzer bir kodla yayımlar. (Bu yaklaşım, bölünmezliği hesaba katmayan basitleştirilmiş bir örnektir.) Bir olayın genellikle kaynak mikro hizmetten veri veya işlem işledikten hemen sonra birden çok mikro hizmete yayılması gerektiğinde benzer kodu uygularsınız.

İlk olarak, aşağıdaki kodda olduğu gibi olay veri yolu uygulama nesnesi (RabbitMQ veya service bus tabanlı) denetleyici oluşturucusunda eklenir:

[Route("api/v1/[controller]")]
public class CatalogController : ControllerBase
{
    private readonly CatalogContext _context;
    private readonly IOptionsSnapshot<Settings> _settings;
    private readonly IEventBus _eventBus;

    public CatalogController(CatalogContext context,
        IOptionsSnapshot<Settings> settings,
        IEventBus eventBus)
    {
        _context = context;
        _settings = settings;
        _eventBus = eventBus;
    }
    // ...
}

Ardından bunu UpdateProduct yöntemindeki gibi denetleyicinizin yöntemlerinden kullanırsınız:

[Route("items")]
[HttpPost]
public async Task<IActionResult> UpdateProduct([FromBody]CatalogItem product)
{
    var item = await _context.CatalogItems.SingleOrDefaultAsync(
        i => i.Id == product.Id);
    // ...
    if (item.Price != product.Price)
    {
        var oldPrice = item.Price;
        item.Price = product.Price;
        _context.CatalogItems.Update(item);
        var @event = new ProductPriceChangedIntegrationEvent(item.Id,
            item.Price,
            oldPrice);
        // Commit changes in original transaction
        await _context.SaveChangesAsync();
        // Publish integration event to the event bus
        // (RabbitMQ or a service bus underneath)
        _eventBus.Publish(@event);
        // ...
    }
    // ...
}

Bu durumda, kaynak mikro hizmeti basit bir CRUD mikro hizmeti olduğundan, bu kod doğrudan bir Web API denetleyicisine yerleştirilir.

CQRS yaklaşımlarını kullanırken olduğu gibi daha gelişmiş mikro hizmetlerde, yöntemi içinde CommandHandler sınıfında Handle() uygulanabilir.

Olay veri yolu'na yayımlarken bölünmezlik ve dayanıklılık tasarlama

Tümleştirme olaylarını olay veri yolunuz gibi dağıtılmış bir mesajlaşma sistemi aracılığıyla yayımladığınızda, özgün veritabanını atomik olarak güncelleştirme ve bir olay yayımlama (her iki işlem de tamamlandı veya hiçbiri) sorunuyla karşınıza çıkar. Örneğin, daha önce gösterilen basitleştirilmiş örnekte kod, ürün fiyatı değiştirildiğinde verileri veritabanına işler ve ardından bir ProductPriceChangedIntegrationEvent iletisi yayımlar. Başlangıçta, bu iki işlemin atomik olarak gerçekleştirilmesi önemli görünebilir. Ancak, Microsoft Message Queuing (MSMQ) gibi eski sistemlerde yaptığınız gibi veritabanı ve ileti aracısı ile ilgili dağıtılmış bir işlem kullanıyorsanız, CAP teoreminde açıklanan nedenlerden dolayı bu yaklaşım önerilmez.

Temel olarak, ölçeklenebilir ve yüksek oranda kullanılabilir sistemler oluşturmak için mikro hizmetleri kullanırsınız. CAP teoreminde bir ölçüde basitleştirerek, sürekli kullanılabilir, güçlü tutarlı ve herhangi bir bölüme dayanıklı bir (dağıtılmış) veritabanı (veya modeline sahip bir mikro hizmet) oluşturamayacağınızı söyler. Bu üç özellik arasından iki tane seçmelisiniz.

Mikro hizmet tabanlı mimarilerde kullanılabilirlik ve toleransı seçmeli ve güçlü tutarlılığı vurgulamalısınız. Bu nedenle, çoğu modern mikro hizmet tabanlı uygulamada, MSMQ ile Windows Dağıtılmış İşlem Düzenleyicisi'ni (DTC) temel alan dağıtılmış işlemleri uygularken yaptığınız gibi, genellikle mesajlaşmada dağıtılmış işlemleri kullanmak istemezsiniz.

İlk soruna ve örneğine geri dönelim. Veritabanı güncelleştirildikten sonra hizmet kilitleniyorsa (bu örnekte, ile _context.SaveChangesAsync()kod satırından hemen sonra), ancak tümleştirme olayı yayımlanmadan önce sistemin tamamı tutarsız hale gelebilir. Bu yaklaşım, ilgilendiğiniz belirli bir iş operasyonuna bağlı olarak iş açısından kritik olabilir.

Mimari bölümünde daha önce belirtildiği gibi, bu sorunla ilgilenmek için çeşitli yaklaşımlarınız olabilir:

  • Olay Kaynağını Belirleme düzeninin tamamını kullanma.

  • İşlem günlüğü madenciliği kullanma.

  • Giden Kutusu düzenini kullanma. Bu, tümleştirme olaylarını depolamak için işlem tablosudur (yerel işlemi genişletir).

Bu senaryo için, tam Olay Kaynağını Belirleme (ES) desenini kullanmak, en iyi yaklaşımlardan biri (en iyi değilse ) biridir . Ancak, birçok uygulama senaryosunda tam bir ES sistemi uygulayamayabilirsiniz. ES, geçerli durum verilerini depolamak yerine yalnızca etki alanı olaylarını işlem veritabanınızda depolamak anlamına gelir. Yalnızca etki alanı olaylarını depolamak, sisteminizin geçmişinin kullanılabilir olması ve geçmişte herhangi bir anda sisteminizin durumunu belirleyebilme gibi büyük avantajlara sahip olabilir. Ancak, tam bir ES sistemi uygulamak için sisteminizin büyük bir bölümünü yeniden oluşturmanız gerekir ve diğer birçok karmaşıklık ve gereksinim ortaya çıkar. Örneğin, Olay Deposu gibi olay kaynağını belirlemek için özel olarak yapılmış bir veritabanı veya Azure Cosmos DB, MongoDB, Cassandra, CouchDB veya RavenDB gibi belge odaklı bir veritabanı kullanmak isteyebilirsiniz. ES bu sorun için harika bir yaklaşımdır, ancak olay kaynağını önceden bilmiyorsanız en kolay çözüm değildir.

İşlem günlüğü madenciliği kullanma seçeneği başlangıçta saydam görünür. Ancak bu yaklaşımı kullanmak için mikro hizmetin SQL Server işlem günlüğü gibi RDBMS işlem günlüğünüzle birleştirilmiş olması gerekir. Bu yaklaşım büyük olasılıkla arzu edilmez. Başka bir dezavantajı, işlem günlüğüne kaydedilen alt düzey güncelleştirmelerin üst düzey tümleştirme olaylarınızla aynı düzeyde olmamasıdır. Öyleyse, bu işlem günlüğü işlemlerini tersine mühendislik işlemi zor olabilir.

Dengeli yaklaşım, işlemsel veritabanı tablosunun ve basitleştirilmiş ES deseninin bir karışımıdır. Tümleştirme olayları tablosuna kaydederken özgün olayda ayarladığınız "olayı yayımlamaya hazır" gibi bir durum kullanabilirsiniz. Ardından olayı olay veri yolu için yayımlamayı deneyin. Olay yayımlama eylemi başarılı olursa, kaynak hizmette başka bir işlem başlatır ve durumu "olayı yayımlamaya hazır" durumundan "olay zaten yayımlanmış" durumuna taşırsınız.

Olay veri yolundaki olay yayımlama eylemi başarısız olursa, veriler kaynak mikro hizmet içinde tutarsız olmaya devam eder; yine de "olayı yayımlamaya hazır" olarak işaretlenir ve hizmetlerin geri kalanıyla ilgili olarak tutarlı olur. her zaman işlemlerin veya tümleştirme olaylarının durumunu denetleen arka plan işleriniz olabilir. İş "olayı yayımlamaya hazır" durumunda bir olay bulursa, bu olayı olay veri yolu için yeniden yayımlamayı deneyebilir.

Bu yaklaşımla yalnızca her kaynak mikro hizmet için tümleştirme olaylarını ve yalnızca diğer mikro hizmetlere veya dış sistemlere iletmek istediğiniz olayları kalıcı hale eklediğinize dikkat edin. Buna karşılık, tam bir ES sisteminde tüm etki alanı olaylarını da depolarsınız.

Bu nedenle bu dengeli yaklaşım basitleştirilmiş bir ES sistemidir. Geçerli durumlarıyla tümleştirme olaylarının bir listesine ("yayımlamaya hazır" ve "yayımlandı") ihtiyacınız vardır. Ancak yalnızca tümleştirme olayları için bu durumları uygulamanız gerekir. Bu yaklaşımda, tüm etki alanı verilerinizi tam bir ES sisteminde olduğu gibi işlem veritabanında olaylar olarak depolamanız gerekmez.

zaten bir ilişkisel veritabanı kullanıyorsanız, tümleştirme olaylarını depolamak için işlem tablosu kullanabilirsiniz. Uygulamanızda bölünmezlik elde etmek için yerel işlemleri temel alan iki adımlı bir işlem kullanırsınız. Temel olarak, etki alanı varlıklarınızın bulunduğu veritabanında bir IntegrationEvent tablonuz vardır. Bu tablo, kalıcı tümleştirme olaylarını etki alanı verilerinizi işleyen işlemlere dahil etmek için bölünmezlik elde etmek için bir sigorta görevi görür.

Adım adım işlem şöyle devam eder:

  1. Uygulama yerel bir veritabanı işlemi başlatır.

  2. Ardından etki alanı varlıklarınızın durumunu güncelleştirir ve tümleştirme olay tablosuna bir olay ekler.

  3. Son olarak işlemi yürüterek istenen bölünmezliği elde edersiniz ve ardından

  4. Olayı bir şekilde yayımlarsınız (sonraki).

Olayları yayımlama adımlarını uygularken şu seçeneklere sahip olursunuz:

  • İşlemi işledikten hemen sonra tümleştirme olayını yayımlayın ve tablodaki olayları yayımlandı olarak işaretlemek için başka bir yerel işlem kullanın. Ardından, uzak mikro hizmetlerde sorun olması durumunda tümleştirme olaylarını izlemek ve depolanan tümleştirme olaylarını temel alan telafi eylemleri gerçekleştirmek için tabloyu bir yapıt olarak kullanın.

  • Tabloyu kuyruk türü olarak kullanın. Ayrı bir uygulama iş parçacığı veya işlem tümleştirme olay tablosunu sorgular, olayları olay veri yolu üzerinde yayımlar ve ardından olayları yayımlandı olarak işaretlemek için yerel bir işlem kullanır.

Şekil 6-22'de bu yaklaşımlardan ilkinin mimarisi gösterilmektedir.

Diagram of atomicity when publishing without a worker microservice.

Şekil 6-22. Olay veri yolu için olayları yayımlarken bölünmezlik

Şekil 6-22'de gösterilen yaklaşımda, yayımlanan tümleştirme olaylarının başarısını denetlemek ve onaylamakla sorumlu ek bir çalışan mikro hizmeti eksiktir. Hata durumunda, bu ek denetleyici çalışanı mikro hizmeti tablodaki olayları okuyabilir ve yeniden yayımlayabilir, yani 2. adımı tekrarlayabilir.

İkinci yaklaşım hakkında: EventLog tablosunu kuyruk olarak kullanırsınız ve iletileri yayımlamak için her zaman bir çalışan mikro hizmeti kullanırsınız. Bu durumda, süreç Şekil 6-23'te gösterilen gibidir. Bu ek bir mikro hizmeti gösterir ve tablo olayları yayımlarken tek kaynaktır.

Diagram of atomicity when publishing with a worker microservice.

Şekil 6-23. Çalışan mikro hizmetiyle olay veriyoluna olay yayımlarken bölünmezlik

Kolaylık olması için eShopOnContainers örneği ilk yaklaşımı (ek işlemler veya denetleyici mikro hizmetleri olmadan) ve olay veri yolunu kullanır. Ancak, eShopOnContainers örneği tüm olası hata durumlarını işlemez. Buluta dağıtılan gerçek bir uygulamada, sorunların sonunda ortaya çıkacağı gerçeğini benimsemeli ve bu denetim ve yeniden gönderme mantığını uygulamanız gerekir. Tabloyu kuyruk olarak kullanmak, bu tabloyu olay veri yolu aracılığıyla yayımlarken (çalışanla) tek bir olay kaynağı olarak kullanıyorsanız ilk yaklaşımdan daha etkili olabilir.

Olay veri yolu aracılığıyla tümleştirme olayları yayımlarken bölünmezlik uygulama

Aşağıdaki kodda, güncelleştirilmekte olan özgün verilerle ilgili bir bağlam ve IntegrationEventLog tablosuyla ilgili ikinci bağlam olmak üzere birden çok DbContext nesnesi içeren tek bir işlemi nasıl oluşturabileceğiniz gösterilmektedir.

Aşağıdaki örnek koddaki işlem, veritabanı bağlantılarında kodun çalıştığı sırada herhangi bir sorun olması durumunda dayanıklı olmayacaktır. Bu durum Azure SQL DB gibi bulut tabanlı sistemlerde gerçekleşebilir ve bu da veritabanlarını sunucular arasında taşıyabilir. Birden çok bağlamda dayanıklı işlemler uygulamak için bu kılavuzun devamında yer alan Dayanıklı Entity Framework Core SQL bağlantılarını uygulama bölümüne bakın.

Netlik sağlamak için aşağıdaki örnekte tüm işlem tek bir kod parçasında gösterilmiştir. Ancak, eShopOnContainers uygulaması yeniden düzenlenir ve bakımı daha kolay olması için bu mantığı birden çok sınıfa böler.

// Update Product from the Catalog microservice
//
public async Task<IActionResult> UpdateProduct([FromBody]CatalogItem productToUpdate)
{
  var catalogItem =
       await _catalogContext.CatalogItems.SingleOrDefaultAsync(i => i.Id ==
                                                               productToUpdate.Id);
  if (catalogItem == null) return NotFound();

  bool raiseProductPriceChangedEvent = false;
  IntegrationEvent priceChangedEvent = null;

  if (catalogItem.Price != productToUpdate.Price)
          raiseProductPriceChangedEvent = true;

  if (raiseProductPriceChangedEvent) // Create event if price has changed
  {
      var oldPrice = catalogItem.Price;
      priceChangedEvent = new ProductPriceChangedIntegrationEvent(catalogItem.Id,
                                                                  productToUpdate.Price,
                                                                  oldPrice);
  }
  // Update current product
  catalogItem = productToUpdate;

  // Just save the updated product if the Product's Price hasn't changed.
  if (!raiseProductPriceChangedEvent)
  {
      await _catalogContext.SaveChangesAsync();
  }
  else  // Publish to event bus only if product price changed
  {
        // Achieving atomicity between original DB and the IntegrationEventLog
        // with a local transaction
        using (var transaction = _catalogContext.Database.BeginTransaction())
        {
           _catalogContext.CatalogItems.Update(catalogItem);
           await _catalogContext.SaveChangesAsync();

           await _integrationEventLogService.SaveEventAsync(priceChangedEvent);

           transaction.Commit();
        }

      // Publish the integration event through the event bus
      _eventBus.Publish(priceChangedEvent);

      _integrationEventLogService.MarkEventAsPublishedAsync(
                                                priceChangedEvent);
  }

  return Ok();
}

ProductPriceChangedIntegrationEvent tümleştirme olayı oluşturulduktan sonra, özgün etki alanı işlemini depolayan işlem (katalog öğesini güncelleştirin) eventLog tablosundaki olayın kalıcılığını da içerir. Bu, bunu tek bir işlem yapar ve olay iletilerinin gönderilip gönderilmediğini her zaman denetleyebilirsiniz.

Olay günlüğü tablosu, aynı veritabanına karşı yerel bir işlem kullanılarak özgün veritabanı işlemiyle atomik olarak güncelleştirilir. İşlemlerden herhangi biri başarısız olursa, bir özel durum oluşturulur ve işlem tamamlanan işlemleri geri alır, böylece etki alanı işlemleri ile tabloya kaydedilen olay iletileri arasında tutarlılığı korur.

Aboneliklerden ileti alma: alıcı mikro hizmetlerde olay işleyicileri

Olay aboneliği mantığına ek olarak, tümleştirme olay işleyicileri için iç kodu (geri çağırma yöntemi gibi) uygulamanız gerekir. Olay işleyicisi, belirli bir türdeki olay iletilerinin alınacağı ve işleneceğini belirttiğiniz yerdir.

Olay işleyicisi önce olay veri yolu'ndan bir olay örneği alır. Ardından bu tümleştirme olayıyla ilgili olarak işlenecek bileşeni bulur ve olayı alıcı mikro hizmetindeki bir durum değişikliği olarak yayarak kalıcı hale getirme. Örneğin, bir ProductPriceChanged olayı katalog mikro hizmetinden kaynaklanıyorsa, sepet mikro hizmetinde işlenir ve aşağıdaki kodda gösterildiği gibi bu alıcı sepeti mikro hizmetindeki durumu da değiştirir.

namespace Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.EventHandling
{
    public class ProductPriceChangedIntegrationEventHandler :
        IIntegrationEventHandler<ProductPriceChangedIntegrationEvent>
    {
        private readonly IBasketRepository _repository;

        public ProductPriceChangedIntegrationEventHandler(
            IBasketRepository repository)
        {
            _repository = repository;
        }

        public async Task Handle(ProductPriceChangedIntegrationEvent @event)
        {
            var userIds = await _repository.GetUsers();
            foreach (var id in userIds)
            {
                var basket = await _repository.GetBasket(id);
                await UpdatePriceInBasketItems(@event.ProductId, @event.NewPrice, basket);
            }
        }

        private async Task UpdatePriceInBasketItems(int productId, decimal newPrice,
            CustomerBasket basket)
        {
            var itemsToUpdate = basket?.Items?.Where(x => int.Parse(x.ProductId) ==
                productId).ToList();
            if (itemsToUpdate != null)
            {
                foreach (var item in itemsToUpdate)
                {
                    if(item.UnitPrice != newPrice)
                    {
                        var originalPrice = item.UnitPrice;
                        item.UnitPrice = newPrice;
                        item.OldUnitPrice = originalPrice;
                    }
                }
                await _repository.UpdateBasket(basket);
            }
        }
    }
}

Olay işleyicisinin, ürünün sepet örneklerinden herhangi birinde mevcut olup olmadığını doğrulaması gerekir. Ayrıca, ilgili her sepet satırı öğesi için madde fiyatını da güncelleştirir. Son olarak, Şekil 6-24'te gösterildiği gibi kullanıcıya fiyat değişikliği hakkında görüntülenecek bir uyarı oluşturur.

Screenshot of a browser showing the price change notification on the user cart.

Şekil 6-24. Tümleştirme olaylarının bildirdiği şekilde sepette bir öğe fiyat değişikliğini görüntüleme

Güncelleştirme iletisi olaylarında bir kez etkili olma

Güncelleştirme iletisi olaylarının önemli bir yönü, iletişimin herhangi bir noktasındaki bir hatanın iletinin yeniden denenmesine neden olmasıdır. Aksi takdirde, bir arka plan görevi zaten yayımlanmış olan bir olayı yayımlamaya çalışabilir ve bir yarış koşulu oluşturabilir. Güncelleştirmelerin bir kez etkili olduğundan veya yinelenen bir öğeyi algılayıp atabileceğinizden ve yalnızca bir yanıt gönderebileceğinizden emin olmak için yeterli bilgi sağladığından emin olun.

Daha önce belirtildiği gibi, bir işlemin sonucu değiştirmeden birden çok kez gerçekleştirilebileceği anlamına gelir. Bir mesajlaşma ortamında, olaylar iletişim kurarken olduğu gibi, alıcı mikro hizmetinin sonucu değiştirilmeden birden çok kez teslim edilebiliyorsa bir olay bir kez etkili olur. Bu, olayın doğası gereği veya sistemin olayı işleme şekli nedeniyle gerekli olabilir. İleti eşzamanlılığı, yalnızca olay veri yolu desenini uygulayan uygulamalarda değil, mesajlaşma kullanan tüm uygulamalarda önemlidir.

Bir kez etkili bir işleme örnek olarak, yalnızca bu veriler tabloda yoksa tabloya veri ekleyen bir SQL deyimi yer alır. Bu insert SQL deyimini kaç kez çalıştırdığınız önemli değildir; sonuç aynı olacaktır; tabloda bu veriler yer alır. İletiler gönderilebilirse ve bu nedenle birden çok kez işlenebilirse, iletilerle ilgilenirken de bunun gibi bir dedempotency gerekebilir. Örneğin, yeniden deneme mantığı bir gönderenin aynı iletiyi birden çok kez göndermesine neden oluyorsa, bunun bir kez etkili olduğundan emin olmanız gerekir.

Bir kez etkili iletiler tasarlamak mümkündür. Örneğin, "ürün fiyatına 5 ABD doları ekleyin" yerine "ürün fiyatını 25 TL olarak ayarlayın" yazan bir olay oluşturabilirsiniz. İlk iletiyi istediğiniz sayıda güvenle işleyebilirsiniz ve sonuç aynı olur. İkinci ileti için bu doğru değildir. Ancak ilk durumda bile ilk olayı işlemek istemeyebilirsiniz çünkü sistem daha yeni bir fiyat değişikliği olayı da göndermiş olabilir ve yeni fiyatın üzerine yazarsınız.

Bir diğer örnek de birden çok aboneye yayılan sipariş tamamlandı olayı olabilir. Aynı sipariş tamamlandı olayı için yinelenen ileti olayları olsa bile, uygulamanın diğer sistemlerde sipariş bilgilerinin yalnızca bir kez güncelleştirildiğinden emin olması gerekir.

Her olayın alıcı başına yalnızca bir kez işlenmesini zorunlu kılan bir mantık oluşturabilmeniz için olay başına bir tür kimliğin olması uygundur.

Bazı ileti işlemeleri doğal olarak bir kez etkili olur. Örneğin, bir sistem görüntü küçük resimleri oluşturuyorsa, oluşturulan küçük resimle ilgili iletinin kaç kez işlendiği önemli olmayabilir; sonuç olarak küçük resimler oluşturulur ve her seferinde aynı olur. Öte yandan, kredi kartından ücret almak için ödeme ağ geçidi çağırma gibi işlemler hiç etkili olmayabilir. Böyle durumlarda, bir iletiyi birden çok kez işlemenin beklediğiniz etkiye sahip olduğundan emin olmanız gerekir.

Ek kaynaklar

Tümleştirme olay iletilerini yinelenenleri kaldırma

İleti olaylarının farklı düzeylerde abone başına yalnızca bir kez gönderilmesini ve işlenmesini sağlayabilirsiniz. Bunun bir yolu, kullandığınız mesajlaşma altyapısı tarafından sunulan yinelenenleri kaldırma özelliğini kullanmaktır. Bir diğeri de hedef mikro hizmetinizde özel mantık uygulamaktır. Doğrulamaların hem aktarım düzeyinde hem de uygulama düzeyinde olması en iyi sonucu sağlar.

EventHandler düzeyinde ileti olaylarını yinelenenleri kaldırma

Bir olayın herhangi bir alıcı tarafından yalnızca bir kez işlenmesini sağlamanın bir yolu, olay işleyicilerinde ileti olaylarını işlerken belirli bir mantık uygulamaktır. Örneğin, bir tümleştirme olayı aldığında UserCheckoutAcceptedIntegrationEvent UserCheckoutAcceptedIntegrationEventHandler sınıfının kaynak kodunda görebileceğiniz gibi eShopOnContainers uygulamasında kullanılan yaklaşım bu şekildedir. (Bu durumda, CreateOrderCommand komutu, komut işleyicisine eventMsg.RequestId gönderilmeden önce tanımlayıcı olarak kullanılarak ile sarmalanırIdentifiedCommand).

RabbitMQ kullanırken iletileri yinelenenleri kaldırma

Aralıklı ağ hataları olduğunda, iletiler yinelenebilir ve ileti alıcısı bu yinelenen iletileri işlemeye hazır olmalıdır. Mümkünse, alıcılar iletileri yinelenenleri kaldırma ile açıkça işlemekten daha iyi olan bir kez etkili bir şekilde işlemelidir.

RabbitMQ belgelerine göre, "Bir ileti bir tüketiciye teslim edilir ve sonra yeniden sorgulanırsa (örneğin, tüketici bağlantısı bırakılmadan önce onaylanmadığı için) RabbitMQ, yeniden teslim edildiğinde (aynı tüketiciye veya farklı bir tüketiciye) yeniden teslim edilen bayrağı ayarlar.

"Yeniden teslim edildi" bayrağı ayarlanırsa, ileti zaten işlenmiş olabileceğinden alıcının bunu hesaba katması gerekir. Ama bu garanti değildir; ileti, ileti aracısını bıraktıktan sonra, ağ sorunları nedeniyle alıcıya hiç ulaşmamış olabilir. Öte yandan, "yeniden teslim edildi" bayrağı ayarlanmamışsa, iletinin birden çok kez gönderilmediği garanti edilir. Bu nedenle, alıcının iletileri yinelenenleri kaldırması veya iletileri yalnızca iletide "yeniden teslim edildi" bayrağı ayarlanmışsa aynı anda işlemesi gerekir.

Ek kaynaklar