Rahaiffeisenpanga .NET-arendajate kogukond jĂ€tkab ViennaNETi sisu lĂŒhivaatlust. Kuidas ja miks me selle juurde jĂ”udsime, .
Selles artiklis kÀsitleme veel mitteoodatud raamatukogusid, mis on seotud hajutatud tehingute, jÀrjekordade ja andmebaasidega, mida leiate meie GitHubi hoidlast (), ja .
ViennaNET.Sagas
Kui projektis toimub ĂŒleminek DDD-le ja mikroteenuste arhitektuurile, siis Ă€riloogika jagamisel erinevatesse teenustesse tekib probleem, mis on seotud hajutatud tehingute mehhanismi rakendamisega, kuna paljud stsenaariumid hĂ”lmavad sageli mitu domeeni. Sellest mehhanismist vĂ”ib lĂ€hemalt tutvuda nĂ€iteks .
Meie projektides oleme rakendanud lihtsa, kuid kasuliku mehhanismi: saga, tÀpsemalt orkestreerimise pÔhine saga. Selle olemus on jÀrgmine: on olemas Àristsenaarium, kus on vaja jÀrjestikku teostada toiminguid erinevates teenustes, samas, kui igal sammul tekib mingeid probleeme, tuleb kutsuda kÔigi eelnevate sammude tagasivÔtmise protseduur, kus see on ette nÀhtud. Seega, sagi lÔpus, sÔltumata edust, saame kÔikides domeenides jÀrjepidevad andmed.
Meie rakendus on seni tehtud baasversioonis ja ei ole seotud teiste teenustega suhtlemiseks. Selle rakendamine ei ole keeruline: piisab, kui luua pÀrija baasabstraktsest klassist SagaBase<T>, kus T on teie konteksti klass, milles saab hoida algandmeid, mis on vajalikud sagi toimimiseks ning mÔned vahe- tulemused. Konteksti eksemplar edastatakse kÔikidesse sammudesse tÀitmise ajal. Ise saga on staateless klass, seetÔttu saab eksemplari DI-s asetada kui Singleton, et saada vajalikud sÔltuvused.
NĂ€idisdeklaratsioon:
public class ExampleSaga : SagaBase<ExampleContext>
{
public ExampleSaga()
{
Step("Step 1")
.WithAction(c => ...)
.WithCompensation(c => ...);
AsyncStep("Step 2")
.WithAction(async c => ...);
}
}
Kutsumise nÀide:
var saga = new ExampleSaga();
var context = new ExampleContext();
await saga.Execute(context);
Erinevate rakenduste tÀielikke nÀiteid saab vaadata ka kogumis koos .
ViennaNET.Orm.*
Raamatukogude komplekt, et töötada erinevate andmebaasidega Nhibernate'i kaudu. Me kasutame DB-First lÀhenemist koos Liquibase'iga, seetÔttu on siin esindatud ainult andmete töötlemise funktsionaalsus valmis andmebaasis.
ViennaNET.Orm.Seedwork ja ViennaNET.Orm on peamised kogud, mis sisaldavad vastavalt pÔhiliideseid ja nende rakendusi. Uurime nende sisu lÀhemalt.
Liides IEntityFactoryService ja selle rakendus EntityFactoryService on pĂ”hipunkt andmebaasiga töötamiseks, kuna siin luuakse Unit of Work, spetsiaalsete entiteetide reposiitoreid ning kĂ€sud ja otsesed SQL-pĂ€ringud. MĂ”nikord on mugav piirata klassi andmebaasiga töötamise vĂ”imalusi, nĂ€iteks lubada ainult andmete lugemist. Sellisteks juhtudeks on IEntityFactoryService oma eelkĂ€ija â liides IEntityRepositoryFactory, kus on deklareeritud ainult meetod reposte loomise jaoks.
Otsese andmebaasi kÔnetamiseks kasutatakse pakkujate mehhanismi. Iga meie meeskondades kasutatava DBMS-i jaoks on oma rakendus: ViennaNET.Orm.MSSQL, ViennaNET.Orm.Oracle, ViennaNET.Orm.SQLite, ViennaNET.Orm.PostgreSql.
Samas vĂ”ib ĂŒhes rakenduses olla samal ajal registreeritud mitu pakkujat, mis vĂ”imaldab, nĂ€iteks, ĂŒhes teenuses ilma infrastruktuuri muutmiseks kulusid kandmata teostada jĂ€rkjĂ€rgulist migratsiooni ĂŒhelt DBMS-ilt teisele. Vajaduse korral vajaliku ĂŒhenduse ja seega pakkuja valimise mehhanism konkreetse klassi entiteedi jaoks (kellele kirjutatakse andmebaasi tabelite mapp) on rakendatud entiteedi registreerimise kaudu BoundedContext klassis (mis sisaldab meetodit domeeni entiteetide registreerimiseks) vĂ”i selle jĂ€rglases ApplicationContextis (mis sisaldab meetodeid rakenduslike entiteetide, otseste pĂ€ringute ja kĂ€skude registreerimiseks), kus argumendina vĂ”etakse ĂŒhenduse identifikaator konfiguratsioonist:
"db": [
{
"nick": "mssql_connection",
"dbServerType": "MSSQL",
"ConnectionString": "...",
"useCallContext": true
},
{
"nick": "oracle_connection",
"dbServerType": "Oracle",
"ConnectionString": "..."
}
],
ApplicationContexti nÀide:
internal sealed class DbContext : ApplicationContext
{
public DbContext()
{
AddEntity("mssql_connection");
AddEntity("oracle_connection");
AddEntity("oracle_connection");
}
}
Kui ĂŒhenduse identifikaatorit ei ole mÀÀratud, kasutatakse ĂŒhendust nimega «default».
Otsene entiteetide mappimine andmebaasi tabelitesse teostatakse standardsete NHibernate vahenditega. Kirjeldust saab kasutada nii xml-failide kaudu kui ka klasside kaudu. Mugavaks repo-zitavate stubide kirjutamiseks Unit-testides on saadaval raamatukogu ViennaNET.TestUtils.Orm.
TÀielikke nÀiteid ViennaNET.Orm.* kasutamisest vÔib leida .
ViennaNET.Messaging.*
Raamatukogude komplekt jÀrjekordadega töötamiseks.
JĂ€rjekordade töötlemisel valiti sama lĂ€henemine kui erinevate andmebaaside puhul, st vĂ”imalikult ĂŒhtne lĂ€henemine raamatukoguga töötamiseks, sĂ”ltumata kasutatavast jĂ€rjekorra haldurist. Raamatukogu ViennaNET.Messaging kannab vastutust selle ĂŒhtsuse eest, ning ViennaNET.Messaging.MQSeriesQueue, ViennaNET.Messaging.RabbitMQQueue ja ViennaNET.Messaging.KafkaQueue sisaldavad adapterite rakendusi vastavalt IBM MQ, RabbitMQ ja Kafka jaoks.
JÀrjekordade töötlemisel on kaks protsessi: sÔnumi vastuvÔtt ja saatmine.
Kaalume vastuvĂ”ttu. Siin on 2 varianti: pidev kuulamine ja ĂŒksiku sĂ”numi vastuvĂ”tt. Pideva kuulamise jaoks tuleb esmalt kirjeldada töötlemisklass, mis on pĂ€rinud klassist IMessageProcessor, mis vastutab sissetuleva sĂ”numi töötlemise eest. SeejĂ€rel tuleb see "siduda" kindla jĂ€rjekorraga, registreerimise teel IQueueReactorFactory konfiguratsioonis mÀÀratud jĂ€rjekorra ID-ga:
"messaging": {
"ApplicationName": "MyApplication"
},
"rabbitmq": {
"queues": [
{
"id": "myQueue",
"queuename": "lalala",
...
}
]
},
NÀide kuulamise kÀivitamisest:
_queueReactorFactory.Register<MyMessageProcessor>("myQueue");
var queueReactor = queueReactorFactory.CreateQueueReactor("myQueue");
queueReactor.StartProcessing();
SeejÀrel, kui teenus kÀivitub ja kutsuda meetod kuulamise alustamiseks, jÔuavad kÔik sÔnumid mÀÀratud jÀrjekorrast vastavasse töötlejasse.
Ăksiku sĂ”numi vastuvĂ”tmiseks interfÀÀri tehase IMessagingComponentFactory on meetod CreateMessageReceiver, mis loob vastuvĂ”tja, kes ootab sĂ”numit antud jĂ€rjekorrast:
using (var receiver = _messagingComponentFactory.CreateMessageReceiver<TestMessage>("myQueue"))
{
var message = receiver.Receive();
}
SÔnumi saatmiseks tuleb kasutada sama IMessagingComponentFactory ja luua sÔnumi saatja:
using (var sender = _messagingComponentFactory.CreateMessageSender<MyMessage>("myQueue"))
{
sender.SendMessage(new MyMessage { Value = ...});
}
SÔnumite serialiseerimiseks ja deserialiseerimiseks on kolm valmidust: lihttekst, XML ja JSON, kuid vajadusel on rahulikult vÔimalik luua oma rakendused liideste jaoks. IMessageSerializer ja IMessageDeserializer.
Oleme pĂŒĂŒdnud sĂ€ilitada iga sĂ”numihalduri unikaalsed vĂ”imalused, nĂ€iteks ViennaNET.Messaging.MQSeriesQueue vĂ”imaldab saata mitte ainult tekstilisi, vaid ka bait-sĂ”numeid, ja ViennaNET.Messaging.RabbitMQQueue toetab reitingut ja jĂ€rjekordade loomist âĂŒhe Ă”hustâ. Meie RabbitMQ adapteri ĂŒmber on ka rakendatud mingi sarnane RPC: saatke sĂ”num ja oodake vastust erilise ajutise jĂ€rjekorra kaudu, mis luuakse ainult ĂŒhe vastussĂ”numi jaoks.
Siin .
ViennaNET.CallContext
Kasutame jĂ€rjekordi mitte ainult erinevate sĂŒsteemide integreerimiseks, vaid ka mikroteenuste suhtlemiseks ĂŒhe rakenduse sees, nĂ€iteks sagade raames. See tĂ”i kaasa vajaduse edastada koos sĂ”numiga selliseid abiteateid nagu kasutaja sisselogimise, pĂ€ringu identifikaator pidevaks logimiseks, lĂ€hte IP-aadress ja autoriseerimisandmed. Nende andmete edastamiseks arendasime vĂ€lja teegi ViennaNET.CallContext, mis vĂ”imaldab salvestada teenuse sissetuleva pĂ€ringu andmed. Sel juhul pole oluline, kuidas pĂ€ring tehti, kas jĂ€rjekorra kaudu vĂ”i Http kaudu. SeejĂ€rel, enne vĂ€ljamineva pĂ€ringu vĂ”i sĂ”numi saatmist, vĂ”etakse kontekstist andmed ja paigutatakse pĂ€istesse. Seega saab jĂ€rgmine teenus abiteateid ja kĂ€sitleb neid vastavalt.
AitÀh tÀhelepanu eest, ootame teie kommentaare ja pull request'e!
Allikas: habr.com
