ViennaNET: kumpulan perpustakaan kanggo backend. Bagean 2

Komunitas pangembang Raiffeisenbank .NET nerusake analisis ringkes babagan konten ViennaNET. Babagan carane lan ngapa kita teka iki, sampeyan bisa maca ing bagean pisanan.

Ing artikel iki, kita bakal nliti sawetara pustaka kanggo nggarap transaksi, antrian, lan basis data sing disebarake sing durung ditutup, sing bisa ditemokake ing repositori GitHub (sumber ing kene), lan Nuget paket kene.

ViennaNET: kumpulan perpustakaan kanggo backend. Bagean 2

ViennaNET.Sagas

Nalika proyek pindhah menyang DDD lan arsitektur microservice, nalika logika bisnis disebarake ing layanan sing beda-beda, ana masalah sing ana hubungane karo kabutuhan kanggo ngleksanakake mekanisme transaksi sing disebarake, amarga akeh skenario asring mengaruhi sawetara domain bebarengan. Sampeyan bisa sinau luwih lengkap babagan mekanisme kasebut, contone, ing buku "Microservices Patterns" dening Chris Richardson.

Ing proyek kita, kita wis ngetrapake mekanisme sing prasaja nanging migunani: saga, utawa luwih tepat, saga adhedhasar orkestrasi. Intine yaiku kaya ing ngisor iki: ana skenario bisnis tartamtu sing kudu terus-terusan nindakake operasi ing layanan sing beda-beda, lan yen ana masalah ing langkah apa wae, perlu nelpon prosedur rollback kabeh langkah sadurunge, sing diwenehake. Mangkono, ing pungkasan eksekusi saga, preduli saka sukses, kita nampa data sing konsisten ing kabeh domain.

Implementasi kita isih dhasar lan ora ngandelake interaksi karo layanan liyane. Gampang digunakake: mung nggawe subclass saka kelas dasar abstrak SagaBase<T>, ing ngendi T minangka kelas konteks sampeyan, ing ngendi sampeyan bisa nyimpen data awal sing dibutuhake supaya saga bisa digunakake, uga sawetara asil penengah. Instance konteks bakal diterusake menyang kabeh langkah sajrone eksekusi. Saga kasebut minangka kelas tanpa negara, mula bisa dilebokake ing DI minangka Singleton kanggo entuk dependensi sing dibutuhake.

Tuladha iklan:

public class ExampleSaga : SagaBase<ExampleContext>
{
  public ExampleSaga()
  {
    Step("Step 1")
      .WithAction(c => ...)
      .WithCompensation(c => ...);
	
    AsyncStep("Step 2")
      .WithAction(async c => ...);
  }
}

Tuladha telpon:

var saga = new ExampleSaga();
var context = new ExampleContext();
await saga.Execute(context);

Conto lengkap implementasine beda bisa dideleng kene lan ing perakitan karo tes.

ViennaNET.Orm.*

Sakumpulan perpustakaan kanggo nggarap macem-macem database liwat Nhibernate. Kita nggunakake pendekatan DB-First nggunakake Liquibase, dadi ing kene mung ana fungsi kanggo nggarap data ing database sing wis siap.

ViennaNET.Orm.Seedwork и ViennaNET.Orm - Majelis utama sing ngemot antarmuka dhasar lan implementasine. Ayo dideleng isine kanthi luwih rinci.

antarmuka IEntityFactoryService lan implementasine EntityFactoryService minangka titik wiwitan utama kanggo nggarap DB, amarga ing kene Unit Kerja digawe, repositori kanggo nggarap entitas tartamtu, uga pelaksana perintah lan pitakon SQL langsung. Kadhangkala trep kanggo matesi kemampuan kelas kanggo nggarap DB, contone, kanggo menehi kemampuan kanggo mung maca data. Kanggo kasus kaya mengkono, IEntityFactoryService ana leluhur - antarmuka IEntityRepositoryFactory, sing nyatakake mung cara kanggo nggawe repositori.

Kanggo akses langsung menyang DB, mekanisme panyedhiya digunakake. Saben DBMS sing digunakake ing printah kita duwe implementasine dhewe: ViennaNET.Orm.MSSQL, ViennaNET.Orm.Oracle, ViennaNET.Orm.SQLite, ViennaNET.Orm.PostgreSql.

Ing kasus iki, sawetara panyedhiya bisa didaftar ing siji aplikasi bebarengan, sing ngidini, contone, kanggo nindakake migrasi langkah-langkah saka siji DBMS menyang liyane ing siji layanan tanpa biaya kanggo modifikasi infrastruktur. Mekanisme kanggo milih sambungan sing dibutuhake lan, akibate, panyedhiya kanggo kelas entitas tartamtu (sing pemetaan menyang tabel DB ditulis) dileksanakake liwat registrasi entitas ing kelas BoundedContext (ngandhut cara kanggo ndhaptar entitas domain) utawa peneruse ApplicationContext (ngemot cara kanggo ndhaptar entitas aplikasi, panjalukan langsung lan perintah i), ing ngendi argumen kasebut minangka konfigurasi:

"db": [
  {
    "nick": "mssql_connection",
    "dbServerType": "MSSQL",
    "ConnectionString": "...",
    "useCallContext": true
  },
  {
    "nick": "oracle_connection",
    "dbServerType": "Oracle",
    "ConnectionString": "..."
  }
],

Contoh Konteks Aplikasi:

internal sealed class DbContext : ApplicationContext
{
  public DbContext()
  {
    AddEntity<SomeEntity>("mssql_connection");
    AddEntity<MigratedSomeEntity>("oracle_connection");
    AddEntity<AnotherEntity>("oracle_connection");
  }
}

Yen ID sambungan ora ditemtokake, sambungan sing jenenge "standar" bakal digunakake.

Pemetaan langsung entitas menyang tabel DB ditindakake kanthi alat NHibernate standar. Sampeyan bisa nggunakake katrangan liwat file xml lan liwat kelas. Kanggo nulis repositori rintisan sing trep ing tes Unit, ana perpustakaan ViennaNET.TestUtils.Orm.

Conto lengkap nggunakake ViennaNET.Orm.* bisa ditemokake kene.

ViennaNET.Pesen.*

Sakumpulan perpustakaan kanggo nggarap antrian.

Pendekatan sing padha dipilih kanggo nggarap antrian kaya karo macem-macem DBMS, yaiku, pendekatan terpadu sing paling mungkin saka sudut pandang nggarap perpustakaan, preduli saka manajer antrian sing digunakake. Pustaka ViennaNET.Messaging sabenere tanggung jawab kanggo manunggalaken iki, lan ViennaNET.Messaging.MQSeriesQueue, ViennaNET.Messaging.RabbitMQQueue и ViennaNET.Messaging.KafkaQueue ngemot implementasi adaptor kanggo IBM MQ, RabbitMQ lan Kafka.

Ana rong proses kanggo nggarap antrian: nampa pesen lan ngirim.

Ayo nimbang nampa. Ana 2 opsi ing kene: kanggo ngrungokake terus-terusan lan kanggo nampa pesen siji. Kanggo terus ngrungokake antrian, sampeyan kudu njlèntrèhaké pisanan kelas prosesor dipun warisaken saka IMessageProcessor, sing bakal tanggung jawab kanggo ngolah pesen sing mlebu. Sabanjure, kudu "disambung" menyang antrian tartamtu, iki rampung liwat registrasi ing IQueueReactorFactory nemtokake pengenal antrian saka konfigurasi:

"messaging": {
    "ApplicationName": "MyApplication"
},
"rabbitmq": {
    "queues": [
      {
        "id": "myQueue",
        "queuename": "lalala",
        ...
      }
    ]
},

Tuladha miwiti ngrungokake:

_queueReactorFactory.Register<MyMessageProcessor>("myQueue");
var queueReactor = queueReactorFactory.CreateQueueReactor("myQueue");
queueReactor.StartProcessing();

Banjur, nalika layanan diwiwiti lan cara kanggo miwiti ngrungokake diarani, kabeh pesen saka antrian sing ditemtokake bakal menyang prosesor sing cocog.

Kanggo nampa pesen siji ing antarmuka pabrik IMessagingComponentFactory ana cara CreateMessageReceiver, sing bakal nggawe panrima sing ngenteni pesen saka antrian sing ditemtokake:

using (var receiver = _messagingComponentFactory.CreateMessageReceiver<TestMessage>("myQueue"))
{
    var message = receiver.Receive();
}

Kanggo ngirim pesen sampeyan kudu nggunakake padha IMessagingComponentFactory lan nggawe pangirim pesen:

using (var sender = _messagingComponentFactory.CreateMessageSender<MyMessage>("myQueue"))
{
    sender.SendMessage(new MyMessage { Value = ...});
}

Ana telung pilihan siap kanggo serialisasi lan deseralisasi pesen: mung teks, XML lan JSON, nanging yen perlu, sampeyan bisa kanthi gampang nggawe implementasine dhewe saka antarmuka. IMessageSerializer и IMessageDeserializer.

Kita nyoba njaga fitur unik saben manajer antrian, contone, ViennaNET.Messaging.MQSeriesQueue ngijini sampeyan kanggo ngirim ora mung pesen teks, nanging uga pesen byte, lan ViennaNET.Messaging.RabbitMQQueue ndhukung nuntun lan nggawe antrian ing fly. Pambungkus adaptor kanggo RabbitMQ uga nindakake sawetara mirip RPC: kita ngirim pesen lan ngenteni respon saka antrian sementara khusus, sing digawe mung kanggo siji pesen respon.

kene conto nggunakake antrian karo nuansa utama sambungan.

ViennaNET.CallContext

Kita nggunakake antrian ora mung kanggo integrasi antarane sistem beda, nanging uga kanggo komunikasi antarane microservices siji aplikasi, contone, ing saga. Iki nyebabake kabutuhan ngirim data tambahan bebarengan karo pesen, kayata login pangguna, njaluk pengenal kanggo logging end-to-end, alamat IP sumber lan data wewenang. Kanggo ngleksanakake nerusake data iki, kita ngembangaken perpustakaan ViennaNET.CallContext, sing ngidini nyimpen data saka panjalukan sing mlebu menyang layanan kasebut. Ing kasus iki, ora ketompo carane panjalukan digawe, liwat antrian utawa liwat Http. Banjur, sadurunge ngirim panjalukan utawa pesen sing metu, data kasebut diekstrak saka konteks lan diselehake ing header. Mangkono, layanan sabanjure nampa data tambahan lan uga ngatur.

Matur nuwun kanggo manungsa waé, kita nunggu komentar lan panjalukan narik!

Source: www.habr.com