Derin Dalış Bahar Modülü Bölüm 2: Olay Mekanizmaları ve Test Stratejileri

Spring Modulith'te olaylar, modülleri gevşek bir şekilde bağlamanın merkezi bir yoludur. Zaman kontrollü olarak devreye alınabiliyor, dış sistemlere aktarılabiliyor ve hedefe yönelik olarak test edilebiliyor. İlk bölümde Spring Boot uygulamasının açıkça tanımlanmış modüllere teknik dökümüne odaklanıldıktan sonra, artık bireysel modüllerin ayrı ayrı ve gerçekçi bir şekilde test edilebileceği diğer olay mekanizmaları ve test stratejilerine odaklanılıyor.

Duyurudan sonra devamını okuyun

Nils Hartmann, arka uçta Java ve ön uçta React konusunda uzmanlaşmış, aynı zamanda atölye çalışmaları ve eğitimler düzenleyen serbest çalışan bir yazılım geliştiricisi ve koçudur.

Bitki bakımı portalı örneği şu ana kadar teknik işleme (“kayıtlı tesis”) gerçekleştikten sonra eylemleri yürüten olayları gösterdi. Üstelik çoğu zaman zaman içinde kontrollü bir şekilde yapılması gereken eylemler de vardır. Örneğin tüm müşteriler için her ay fatura oluşturulup gönderilmelidir. Ek açıklama kullanılarak Spring Boot'ta zamanlanmış eylemler gerçekleştirilebilir @Scheduled alet. Örneğin, bu bir cron-Açıklamalı yöntemin ne zaman yürütüleceğini belirleyen geçiş ifadesi. Ancak bu tür yöntemlerin test edilmesi zordur. Açıklanan örnekte, fatura oluşturma testi, Spring'in zamanlanmış yöntemi çağırmasını sağlamak için zamanı yapay olarak ayarlamalıdır. Ayrıca bir tane var cron– Daha az anlamlı ifade, çünkü zamanları (“her ayın ilk günü sabah saat 3'te”) belirtir, ancak olayları (“ay değişti”) göstermez.

Spring Modulith'in bir parçası olan Moments API ile yinelenen eylemleri gerçekleştirmenin başka bir yolu vardır. Spring Modulith'in bir dönem sonunda tetiklediği (örneğin saatlik, günlük veya üç aylık değişiklikler) ve uygulama tarafından tüketilebilen bir dizi olaydan oluşur. Örneğin, etkinliğe ayın başında erişebilirsiniz. MonthHasPassed Tepki verin. İşleme normal olaylarda olduğu gibi gerçekleşir. @EventListener İstenilen olay türünü argüman olarak alan açıklamalı yöntem. Liste 1 örnek olarak kullanımı göstermektedir InvoiceGeneratoray sonunda fatura oluşturur.

Liste 1: InoviceGenerator bu ayın sonunda açıklanacak MomentHasPassed-Olay tetiklendi


package nh.demo.plantify.billing.invoice;

import org.springframework.context.event.EventListener;
import org.springframework.modulith.moments.MonthHasPassed;
// ...

@Component
class InvoiceGenerator {

    // ...


    @EventListener
    @Transactional
    void generateInvoices(MonthHasPassed event) {
        
        var month = event.getMonth();
        // Rechnungen für den Monat month erzeugen
        // ...
    }
}

Bu varyantın avantajı, olay anlarını içeren kodun anlaşılmasının, kullanılmasından daha kolay olmasıdır. @Schedulerolaylar aynı zamanda yararlı bilgiler de sağlar (ör. hangi ayın geçtiği). Fasulye TimeMaschineSpring Modulith'in uygulama bağlamında otomatik olarak kayıt yapması, olayları tetiklemesi. Test için süre yapay olarak uzatılabilir. Normalde bu hızlandırılmış zaman diliminde tetiklenecek tüm olaylar, testte de tetiklenecektir.

Duyurudan sonra devamını okuyun

Uygulama şunları kullanır: ApplicationEventPublishermesleki etkinlikleri uygulama içinde yayınlamak. Spring Modulith ile olaylar Kafka, RabbitMQ veya JMS sunucusu gibi harici sistemlere de aktarılabilir. Bu amaçla Spring Modulith, uygulamanızın Maven veya Gradle konfigürasyonu aracılığıyla entegre edilebilecek komisyoncuya özel başlangıç ​​modülleri sağlar.

Ek açıklama @Externalized Bir olay sınıfı, olayın harici bir sisteme gönderilmesi gerektiğini ifade eder. Liste 2 bunu gösteriyor InvoiceCreatedEventbaşvuruyu Kafka'ya gönderir. THE target-Öznitelik, olayın nasıl yönlendirilmesi gerektiğini belirten aracıya özgü bir ifade içerir. Örnekte olay Kafka konusuna gönderiliyor invoices etkinliğe eklenenle birlikte gönderildi ownerId mesajın anahtarını oluşturur.

Liste 2: Kafka aracılığıyla yayınlanan bir uygulama etkinliği


package nh.demo.plantify.billing.invoice;


import org.springframework.modulith.events.Externalized;
// ...


@Externalized(target = "invoices::#{#this.ownerId()}")
public record InvoiceGeneratedEvent(
    UUID ownerId,
    YearMonth billingPeriod,
    BigDecimal amount
) { }

Gelecek sürüm 2.1'de Spring Modulith, gönderim için giden posta modelini uyguluyor @Externalized-Olaylar. Bu, her olayın harici sisteme en az bir kez başarıyla iletilmesini sağlar. Bu amaçla, Spring Boot uygulamaları için Giden Kutusu modelinin uygulanmasını sağlayan Namastack çerçevesi dahili olarak kullanılır. Uygulamanızın davranışını etkinleştirmek için bir Spring özelliği ayarlamanız yeterlidir. Bu özelliğin duyurulmasının bir parçası olarak, Roland Beisel (Namastack Outbox başkanı) ve Gunnar Morling (Debezium'un eski teknoloji başkanı) arasında Namastack'ın spesifik uygulaması ve sonuçları hakkında ilginç bir tartışma gelişti.

Teknik işleme bağlamında, bir uygulama verileri kendi veritabanına kaydedebilir veya harici bir sisteme bir olay gönderebilir (@Externalized). Ancak harici bir olayın gönderilmesi veritabanı işleminin bir parçası değildir. Bu nedenle, işlem başarıyla onaylandıysa ancak olay teslim edilemiyorsa (örneğin, mesaj aracısında bağlantı sorunları olması nedeniyle), olay kaybolur. Örnekte uygulama bir fatura oluşturup kaydetmişti ancak fatura etkinlik yoluyla teslim edilemiyordu.

Sırayı tersine çevirseniz, yani olayın başarıyla gönderilmesini bekleyip uygulama işlemi onaylasa bile bir tutarsızlık meydana gelebilir. Bu takımyıldızında, olayın harici sisteme iletilmesi mümkündür ancak uygulama daha sonra işlemini onaylayamaz. Yani Spring gönderilen olayı alamıyor. Örnek uygulamada bu, harici sistemin uygulamada bile bilinmeyen bir fatura alması anlamına gelir.

Bu sorunu çözmek için bir uygulama Giden Kutusu şablonunu kullanabilir. Yani uygulama olayı hemen göndermez, bunun yerine işlem tamamlandığında onu veritabanındaki diğer verilerle birlikte kendi tablosunda saklar. Bu tablo bir giden kutusu görevi görür. Ancak o zaman uygulama, olayı giden tablodan yeni bir işlemde teslim etmeye çalışır. Bir hata oluşursa, uygulamanın daha sonra tekrar göndermeyi deneyebilmesi için olay tabloda kalır. Uygulama olayı başarıyla gönderdikten sonra onu veritabanından kaldırır ve işlemi tamamlar. Bir hata oluşursa ve işlem gerçekleştirilemezse, olay daha önce harici sisteme başarıyla gönderilmiş olsa bile giden kutusu tablosunda kalır. Etkinlik hâlâ giden kutusu tablosunda olduğundan uygulama bir sonraki çalıştırmada etkinliği yeniden göndermeyi deneyecektir. Bu, alıcının olayı birden fazla kez alabileceği anlamına gelir, ancak bu şekilde uygulama, etkinliğin en az bir kez iletildiğini ve tamamen kaybolmadığını (“en az bir kez” anlambilimi) garanti edebilir. Bu nedenle alıcının bir olayı birden çok kez almayı beklemesi ve örneğin işleme sırasında yinelenen olayları göz ardı etmesi (aynılık) gerekir. Bu, sistemler arasında gerçek işlemlerin mümkün olmadığı veya çok karmaşık olduğu dağıtılmış sistemlerde tipik bir modeldir.

Bu noktaya kadar odak noktası Java kodunu bağımsız uygulama modüllerine bölmekti. Bir uygulama genellikle örneğin Flyway tarafından yönetilen veritabanı için geçiş komut dosyalarını da içerir. Spring Boot, uygulama başlatıldığında bunu otomatik olarak yapar ve veritabanının uygulamanın mevcut sürümüne uygun düzeyde olmasını sağlar. Genellikle bir uygulamanın geçiş komut dosyaları merkezi bir konumda bulunur migrationdizini adında sürüm numarası bulunan bir dosya olarak kullanın. Ancak geçiş komut dosyalarının merkezi yönetimi ve sürümlendirilmesi, modülerleştirme fikriyle çelişmektedir.

Bu nedenle Spring Modulith, scriptlerin sadece merkezi olarak değil, modül bazında saklanması ve versiyon kontrol imkanı sunmaktadır. Bu, her modülün kendi geçiş komut dosyası geçmişini korumasına olanak tanır. Genel sıralama modül bağımlılıklarından kaynaklanır. Modüle özgü Flyway dosyaları, ilgili modülle aynı ada sahip bir alt klasörde saklanmalıdır. Ayrıca dizin geliyor __kök küresel geçiş komut dosyalarının yerinin olduğu yerlerde kullanım için. Uygulama, komut dosyalarını her zaman önce bu dizinde çalıştırır. Şekil 1 Plantify geçiş komut dosyalarını göstermektedir.

Veritabanı için modülerleştirilmiş Flyway geçiş komut dosyaları

Veritabanı için modülerleştirilmiş Flyway geçiş komut dosyaları

Veritabanı için modülerleştirilmiş Flyway geçiş komut dosyaları (Şekil 1)

(Fotoğraf: Nils Hartmann)

Modül yapısının veritabanında da korunmasını sağlamak için her modül Postgres'te kendi veritabanı şemasını tanımlar. içinde __kökKlasör, Olay Yayın Günlüğüne ilişkin tabloları oluşturmaya yönelik komut dosyalarını içerir. Bir entegrasyon testinde Spring Modulith her zaman yalnızca modülü o anda test edilen komut dosyalarını çalıştırır ve komut dosyaları arasında istenmeyen referansların olmamasını sağlar.


Yayımlandı

kategorisi

yazarı:

Etiketler:

Yorumlar

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir