A Raiffeisenbank .NET fejlesztői közössége továbbra is röviden áttekinti a ViennaNET tartalmát. Arról, hogyan és miért jutottunk idáig,
Ebben a cikkben az elosztott tranzakciókkal, várólistákkal és adatbázisokkal való munkavégzéshez szükséges, még megfontolás tárgyát képező könyvtárakat tekintjük át, amelyek a GitHub tárhelyünkben találhatók (
ViennaNET.Sagas
Amikor egy projekt DDD-re és mikroszolgáltatási architektúrára vált, akkor amikor az üzleti logika különböző szolgáltatások között van elosztva, probléma merül fel az elosztott tranzakciós mechanizmus megvalósításának szükségességével kapcsolatban, mivel sok forgatókönyv gyakran több tartományt érint egyszerre. Az ilyen mechanizmusokkal részletesebben megismerkedhet, pl.
Projektjeinkben egy egyszerű, de hasznos mechanizmust valósítottunk meg: egy saga, vagy inkább egy hangszerelés alapú saga. Lényege a következő: van egy bizonyos üzleti forgatókönyv, amelyben egymás után kell végrehajtani a műveleteket a különböző szolgáltatásokban, és bármilyen probléma esetén bármely lépésben meg kell hívni az összes korábbi lépés visszaállítási eljárását, ahol biztosított. Így a saga végén a sikertől függetlenül minden területen konzisztens adatokat kapunk.
Megvalósításunk továbbra is alapvető formában történik, és nem kötődik más szolgáltatásokkal való interakciós módszerek használatához. Használata nem nehéz: csak készítse el a SagaBase alap absztrakt osztály leszármazottját, ahol T a kontextus osztálya, amelyben tárolhatja a saga működéséhez szükséges kezdeti adatokat, valamint néhány köztes eredményt. A kontextuspéldány a végrehajtás során minden lépésre átkerül. A Saga maga egy állapot nélküli osztály, így a példányt Singletonként lehet elhelyezni a DI-ben, hogy megkapja a szükséges függőségeket.
Példahirdetés:
public class ExampleSaga : SagaBase<ExampleContext>
{
public ExampleSaga()
{
Step("Step 1")
.WithAction(c => ...)
.WithCompensation(c => ...);
AsyncStep("Step 2")
.WithAction(async c => ...);
}
}
Példahívás:
var saga = new ExampleSaga();
var context = new ExampleContext();
await saga.Execute(context);
A különböző megvalósítások teljes példái megtekinthetők
ViennaNET.Orm.*
Könyvtárkészlet különféle adatbázisokkal való munkavégzéshez a Nhibernate segítségével. A Liquibase segítségével a DB-First megközelítést használjuk, így csak egy kész adatbázisban lévő adatokkal való munkavégzésre van lehetőség.
ViennaNET.Orm.Seedwork и ViennaNET.Orm
– az alapvető interfészeket tartalmazó főösszeállítások és azok megvalósításai, ill. Nézzük meg részletesebben a tartalmukat.
felület IEntityFactoryService
és annak végrehajtása EntityFactoryService
az adatbázissal való munkavégzés fő kiindulópontja, hiszen itt jönnek létre a Munkaegység, az adott entitásokkal való munkavégzéshez szükséges tárolók, valamint a parancsok végrehajtói és a közvetlen SQL lekérdezések. Néha célszerű korlátozni egy osztály képességeit egy adatbázissal való munkavégzéshez, például annak érdekében, hogy lehetővé tegye csak az adatok olvasását. Ilyen esetekre IEntityFactoryService
van egy ős - interfész IEntityRepositoryFactory
, amely csak egy adattárak létrehozásának módszerét deklarálja.
Az adatbázis közvetlen eléréséhez a szolgáltatói mechanizmust használják. Minden csapatunkban használt DBMS-nek megvan a maga megvalósítása: ViennaNET.Orm.MSSQL, ViennaNET.Orm.Oracle, ViennaNET.Orm.SQLite, ViennaNET.Orm.PostgreSql
.
Ugyanakkor egyszerre több szolgáltató is regisztrálható egy alkalmazásban, ami lehetővé teszi például egy szolgáltatás keretén belül, az infrastruktúra módosításának költsége nélkül lépésről lépésre történő migrációt egyik DBMS-ről a másikra. A szükséges kapcsolat és így egy adott entitásosztály szolgáltatójának kiválasztásának mechanizmusa (amelyhez adatbázistáblázatokhoz való leképezés van írva) úgy valósul meg, hogy az entitást a BoundedContext osztályba (amely egy tartományi entitások regisztrálására szolgáló metódust tartalmaz) vagy annak utódjába regisztrálják. ApplicationContext (az alkalmazás entitások regisztrálásának metódusait, közvetlen kéréseket és parancsokat tartalmazza), ahol a konfigurációból származó kapcsolatazonosító elfogadásra kerül argumentumként:
"db": [
{
"nick": "mssql_connection",
"dbServerType": "MSSQL",
"ConnectionString": "...",
"useCallContext": true
},
{
"nick": "oracle_connection",
"dbServerType": "Oracle",
"ConnectionString": "..."
}
],
Példa ApplicationContext:
internal sealed class DbContext : ApplicationContext
{
public DbContext()
{
AddEntity<SomeEntity>("mssql_connection");
AddEntity<MigratedSomeEntity>("oracle_connection");
AddEntity<AnotherEntity>("oracle_connection");
}
}
Ha a csatlakozási azonosító nincs megadva, akkor a „default” nevű kapcsolat kerül felhasználásra.
Az entitások adatbázistáblákhoz való közvetlen hozzárendelése szabványos NHibernate eszközökkel valósul meg. A leírást xml-fájlokon és osztályokon keresztül egyaránt használhatja. Az egységtesztekben a csonktárolók kényelmes írásához van egy könyvtár ViennaNET.TestUtils.Orm
.
A ViennaNET.Orm.* használatára teljes példák találhatók
ViennaNET.Messaging.*
Könyvtárak készlete a sorokkal való munkához.
A sorokkal való munkához ugyanazt a megközelítést választottuk, mint a különféle DBMS-eknél, nevezetesen a lehető legnagyobb egységes megközelítést a könyvtárral való munkavégzés szempontjából, függetlenül a használt sorkezelőtől. Könyvtár ViennaNET.Messaging
pontosan felelős ezért az egyesülésért, és ViennaNET.Messaging.MQSeriesQueue, ViennaNET.Messaging.RabbitMQQueue и ViennaNET.Messaging.KafkaQueue
adapter implementációkat tartalmaznak az IBM MQ, RabbitMQ és Kafka számára.
A sorokkal való munka során két folyamat van: egy üzenet fogadása és elküldése.
Fontolja meg az átvételt. Itt 2 lehetőség van: folyamatos hallgatásra és egyetlen üzenet fogadására. A sor folyamatos figyeléséhez először le kell írnia a processzorosztályt, amelyből örökölt IMessageProcessor
, amely a bejövő üzenet feldolgozásáért lesz felelős. Ezután egy adott sorhoz kell „kapcsolni”; ez regisztrációval történik IQueueReactorFactory
a sor azonosítójának megadása a konfigurációból:
"messaging": {
"ApplicationName": "MyApplication"
},
"rabbitmq": {
"queues": [
{
"id": "myQueue",
"queuename": "lalala",
...
}
]
},
Példa a hallgatás megkezdésére:
_queueReactorFactory.Register<MyMessageProcessor>("myQueue");
var queueReactor = queueReactorFactory.CreateQueueReactor("myQueue");
queueReactor.StartProcessing();
Ezután, amikor a szolgáltatás elindul, és a metódus meghívásra kerül a figyelés megkezdéséhez, a megadott sor összes üzenete a megfelelő processzorhoz kerül.
Egyetlen üzenet fogadása gyári felületen IMessagingComponentFactory
van egy módszer CreateMessageReceiver
amely létrehoz egy címzettet, aki üzenetre vár a neki megadott sorból:
using (var receiver = _messagingComponentFactory.CreateMessageReceiver<TestMessage>("myQueue"))
{
var message = receiver.Receive();
}
Üzenet küldéséhez ugyanazt kell használnod IMessagingComponentFactory
és hozzon létre egy üzenetküldőt:
using (var sender = _messagingComponentFactory.CreateMessageSender<MyMessage>("myQueue"))
{
sender.SendMessage(new MyMessage { Value = ...});
}
Három kész lehetőség van egy üzenet szerializálására és deszerializálására: csak szöveg, XML és JSON, de szükség esetén könnyedén elkészítheti saját interfész implementációit. IMessageSerializer и IMessageDeserializer
.
Igyekeztünk megőrizni az egyes sorkezelők egyedi képességeit, pl. ViennaNET.Messaging.MQSeriesQueue
nem csak szöveges, hanem bájtos üzenetek küldését is lehetővé teszi, ill ViennaNET.Messaging.RabbitMQQueue
támogatja az útválasztást és az on-the-fly sorban állást. A RabbitMQ-hoz készült adapterburkolónk is megvalósítja az RPC némi látszatát: üzenetet küldünk, és egy speciális ideiglenes sorból várunk választ, amely csak egy válaszüzenethez jön létre.
Itt
ViennaNET.CallContext
A sorokat nem csak a különböző rendszerek közötti integrációhoz használjuk, hanem ugyanazon alkalmazás mikroszolgáltatásai közötti kommunikációhoz is, például egy sagán belül. Ez ahhoz vezetett, hogy az üzenettel együtt olyan segédadatokat kellett továbbítani, mint a felhasználói bejelentkezés, a végpontok közötti naplózás kérési azonosítója, a forrás IP-címe és az engedélyezési adatok. Ezen adatok továbbításának megvalósítására könyvtárat fejlesztettünk ki ViennaNET.CallContext
, amely lehetővé teszi a szolgáltatásba belépő kérés adatainak tárolását. Ebben az esetben nem számít, hogy a kérés hogyan történt, soron keresztül vagy Http-n keresztül. Ezután a kimenő kérés vagy üzenet elküldése előtt a rendszer az adatokat a kontextusból veszi és a fejlécekbe helyezi. Így a következő szolgáltatás fogadja a segédadatokat, és ugyanúgy kezeli azokat.
Köszönjük figyelmüket, várjuk észrevételeiket, kéréseiteket!
Forrás: will.com