ViennaNET: backend-erako liburutegi multzo bat. 2. zatia

Raiffeisenbank .NET garatzaileen komunitateak ViennaNET-en edukien azterketa laburra egiten jarraitzen du. Nola eta zergatik heldu ginen honetara, lehen zatia irakur dezakezu.

Artikulu honetan, oraindik kontuan hartu gabeko liburutegiak aztertuko ditugu banatutako transakzioekin, ilarekin eta datu-baseekin lan egiteko, gure GitHub biltegian aurki daitezkeenak (iturriak hemen daude), eta Nuget paketeak hemen.

ViennaNET: backend-erako liburutegi multzo bat. 2. zatia

ViennaNET.Sagas

Proiektu bat DDD eta mikrozerbitzuen arkitekturara aldatzen denean, orduan negozio-logika zerbitzu ezberdinetan banatzen denean, arazo bat sortzen da banatutako transakzio-mekanismo bat ezartzeko beharrarekin lotuta, eszenatoki askok askotan hainbat domeinuri eragiten dietelako aldi berean. Horrelako mekanismoak zehatzago ezagutu ditzakezu, adibidez, "Microservices Patterns" liburuan, Chris Richardson.

Gure proiektuetan mekanismo sinple baina erabilgarria ezarri dugu: saga bat, edo hobeto esanda, orkestrazioan oinarritutako saga bat. Bere funtsa honakoa da: negozio-eszenatoki jakin bat dago, non zerbitzu ezberdinetan eragiketak sekuentzialki egitea beharrezkoa den, eta edozein pausotan arazoren bat izanez gero, aurreko urrats guztien itzulera prozedura deitu behar da, non. ematen da. Horrela, sagaren amaieran, arrakasta gorabehera, datu koherenteak jasotzen ditugu domeinu guztietan.

Gure inplementazioa oinarrizko forman egiten da oraindik eta ez dago beste zerbitzu batzuekin elkarrekintza-metodoren erabilerarekin lotuta. Ez da zaila erabiltzea: SagaBase<T> oinarrizko klase abstraktuaren ondorengo bat egin besterik ez dago, non T zure testuinguruko klasea den eta bertan sagak funtziona dezan beharrezkoak diren hasierako datuak gorde ditzakezu, baita tarteko emaitza batzuk ere. Testuinguruaren instantzia urrats guztietara pasatuko da exekuzioan zehar. Saga bera estaturik gabeko klasea da, beraz, instantzia DIn jar daiteke Singleton gisa, beharrezko mendekotasunak lortzeko.

Iragarki adibidea:

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

Deiaren adibidea:

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

Inplementazio desberdinen adibide osoak ikus daitezke Hemen eta batzarrean probak.

ViennaNET.Orm.*

Nhibernate bidez hainbat datu-baseekin lan egiteko liburutegi multzoa. DB-First ikuspegia erabiltzen dugu Liquibase erabiliz, beraz, prest dauden datu-base batean datuekin lan egiteko funtzionaltasuna besterik ez dago.

ViennaNET.Orm.Seedwork и ViennaNET.Orm – Oinarrizko interfazeak eta horien ezarpenak dituzten multzo nagusiak, hurrenez hurren. Ikus ditzagun haien edukia zehatzago.

interface IEntityFactoryService eta haren ezarpena EntityFactoryService datu-basearekin lan egiteko abiapuntu nagusia dira, Lan Unitatea, entitate zehatzekin lan egiteko biltegiak, baita komandoen exekutatzaileak eta SQL zuzeneko kontsultak sortzen baitira hemen. Batzuetan komenigarria da klase baten gaitasunak mugatzea datu-base batekin lan egiteko, adibidez, datuak soilik irakurtzeko gaitasuna eskaintzea. Horrelako kasuetarako IEntityFactoryService arbaso bat dago - interfazea IEntityRepositoryFactory, biltegiak sortzeko metodo bat soilik deklaratzen duena.

Datu-basera zuzenean sartzeko, hornitzailearen mekanismoa erabiltzen da. Gure taldeetan erabiltzen dugun DBMS bakoitzak bere inplementazioa du: ViennaNET.Orm.MSSQL, ViennaNET.Orm.Oracle, ViennaNET.Orm.SQLite, ViennaNET.Orm.PostgreSql.

Aldi berean, hainbat hornitzaile erregistratu daitezke aplikazio batean aldi berean, eta horri esker, adibidez, zerbitzu baten esparruan, azpiegitura aldatzeko kosturik gabe, urratsez urratseko migrazioa egin daiteke. DBMS bat bestera. Beharrezko konexioa eta, beraz, entitate-klase zehatz baterako hornitzailea (horretarako datu-baseen taulen mapak idazten diren) hautatzeko mekanismoa BoundedContext klasean (domeinu-entitateak erregistratzeko metodo bat dauka) edo haren ondorengoa erregistratuz ezartzen da. ApplicationContext (aplikazio-entitateak, zuzeneko eskaerak eta komandoak erregistratzeko metodoak ditu), non konfigurazioko konexio-identifikatzailea argumentu gisa onartzen den:

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

Aplikazioaren testuingurua adibidea:

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

Konexioaren IDa zehazten ez bada, "lehenetsia" izeneko konexioa erabiliko da.

Entitateen zuzeneko mapaketa datu-baseen taulekin inplementatzen da NHibernate tresna estandarrak erabiliz. Deskribapena xml fitxategien eta klaseen bidez erabil dezakezu. Unitate-probetan zirriborroen biltegiak idazteko, liburutegi bat dago ViennaNET.TestUtils.Orm.

ViennaNET.Orm.* erabiltzearen adibide osoak aurki daitezke Hemen.

ViennaNET.Mezularitza.*

Ilarekin lan egiteko liburutegi multzoa.

Ilarekin lan egiteko, hainbat DBMSrekin egiten den ikuspegi bera aukeratu zen, hots, liburutegiarekin lan egiteko ahalik eta hurbilpen bateratu handiena, erabilitako ilararen kudeatzailea edozein dela ere. Liburutegia ViennaNET.Messaging da hain zuzen bateratze horren arduraduna, eta ViennaNET.Messaging.MQSeriesQueue, ViennaNET.Messaging.RabbitMQQueue и ViennaNET.Messaging.KafkaQueue IBM MQ, RabbitMQ eta Kafka-ren egokitzaileen inplementazioak dituzte, hurrenez hurren.

Ilarekin lan egitean, bi prozesu daude: mezu bat jasotzea eta bidaltzea.

Demagun jasotzea. 2 aukera daude hemen: etengabe entzuteko eta mezu bakarra jasotzeko. Ilara etengabe entzuteko, lehenik eta behin heredatutako prozesadore-klasea deskribatu behar duzu IMessageProcessor, sarrerako mezua prozesatzeaz arduratuko dena. Ondoren, ilara zehatz bati "lotua" egon behar da; hau erregistratzearen bidez egiten da IQueueReactorFactory konfigurazioko ilararen identifikatzailea adieraziz:

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

Entzuten hasteko adibidea:

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

Ondoren, zerbitzua abiarazten denean eta metodoari entzuten hasteko, zehaztutako ilararen mezu guztiak dagokion prozesadorera joango dira.

Mezu bakarra fabrikako interfaze batean jasotzeko IMessagingComponentFactory metodo bat dago CreateMessageReceiverhorrek zehaztutako ilaratik mezu baten zain dagoen hartzaile bat sortuko du:

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

Mezu bat bidaltzeko bera erabili behar duzu IMessagingComponentFactory eta sortu mezu igorle bat:

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

Mezu bat serializatu eta deserializatzeko prest dauden hiru aukera daude: testua, XML eta JSON besterik ez, baina beharrezkoa izanez gero, erraz egin ditzakezu zure interfazearen inplementazioak. IMessageSerializer и IMessageDeserializer.

Ilara kudeatzaile bakoitzaren gaitasun bereziak gordetzen saiatu gara, adibidez. ViennaNET.Messaging.MQSeriesQueue Testua ez ezik, byte-mezuak ere bidaltzeko aukera ematen du, eta ViennaNET.Messaging.RabbitMQQueue bideraketa eta hegan ilarak onartzen ditu. RabbitMQ-rako gure moldagailuak RPC itxuraren bat ere inplementatzen du: mezu bat bidaltzen dugu eta aldi baterako ilara berezi baten erantzuna itxarongo dugu, erantzun-mezu baterako bakarrik sortzen dena.

Hemen oinarrizko konexio ñabardurak dituzten ilarak erabiltzeko adibidea.

ViennaNET.CallContext

Sistema ezberdinen arteko integraziorako ez ezik, aplikazio bereko mikrozerbitzuen arteko komunikaziorako ere erabiltzen ditugu ilarak, adibidez, saga baten barruan. Horrek mezuarekin batera datu osagarriak transmititu beharra ekarri zuen, hala nola erabiltzailearen saioa, amaierako erregistrorako eskaeraren identifikatzailea, iturriko IP helbidea eta baimen-datuak. Datu horien bidalketa gauzatzeko, liburutegi bat garatu dugu ViennaNET.CallContext, zerbitzuan sartzen den eskaera baten datuak gordetzeko aukera ematen duena. Kasu honetan, eskaera nola egin den, ilara baten bidez edo Http bidez, ez du axola. Ondoren, irteerako eskaera edo mezua bidali aurretik, datuak testuingurutik hartu eta goiburuetan jartzen dira. Horrela, hurrengo zerbitzuak datu laguntzaileak jasotzen ditu eta era berean kudeatzen ditu.

Eskerrik asko zure arretagatik, zure iruzkinak eta tira eskaerak espero ditugu!

Iturria: www.habr.com

Gehitu iruzkin berria