ViennaNET: taustaprogrammi teekide komplekt. 2. osa

Raiffeisenbank .NET arendajate kogukond jätkab ViennaNETi sisu lühiajalist ülevaatamist. Kuidas ja miks me selleni jõudsime, saate lugeda esimest osa.

Selles artiklis käsitleme hajutatud tehingute, järjekordade ja andmebaasidega töötamiseks veel kaalumata teeke, mille leiate meie GitHubi hoidlast (allikad on siin) ja Nugeti paketid siin.

ViennaNET: taustaprogrammi teekide komplekt. 2. osa

ViennaNET.Sagas

Kui projekt läheb üle DDD ja mikroteenuse arhitektuurile, siis äriloogika jaotamisel erinevate teenuste vahel tekib probleem seoses hajutatud tehingumehhanismi juurutamise vajadusega, kuna paljud stsenaariumid mõjutavad sageli mitut domeeni korraga. Selliste mehhanismidega saate lähemalt tutvuda, näiteks raamatus "Microservices Patterns", Chris Richardson.

Oleme oma projektides rakendanud lihtsa, kuid kasuliku mehhanismi: saaga, õigemini orkestratsioonipõhise saaga. Selle olemus on järgmine: on teatud äristsenaarium, mille puhul on vaja erinevates teenustes toiminguid teha järjestikku ja kui mis tahes etapis ilmnevad probleemid, on vaja kõigi eelnevate sammude jaoks tagasipööramise protseduur kutsuda, kus see on ette nähtud. Seega saame saaga lõpus, hoolimata edust, ühtsed andmed kõigis valdkondades.

Meie juurutamine on endiselt põhikujul ega ole seotud muude teenustega suhtlemise meetodite kasutamisega. Seda pole keeruline kasutada: tehke lihtsalt abstraktse baasklassi SagaBase<T> järeltulija, kus T on teie kontekstiklass, kuhu saate salvestada saaga toimimiseks vajalikud algandmed ja mõned vahetulemused. Kontekstieksemplar edastatakse täitmise ajal kõikidele etappidele. Saga ise on olekuta klass, nii et eksemplari saab vajalike sõltuvuste saamiseks paigutada DI-sse Singletonina.

Näidisreklaam:

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

Kõne näide:

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

Erinevate rakenduste täielikke näiteid saab vaadata siin ja koos testid.

ViennaNET.Orm.*

Teekide komplekt erinevate andmebaasidega töötamiseks Nhibernate'i kaudu. Kasutame Liquibase'i abil DB-First lähenemist, seega on olemas ainult valmisandmebaasis olevate andmetega töötamise funktsionaalsus.

ViennaNET.Orm.Seedwork и ViennaNET.Orm – põhikooste, mis sisaldavad vastavalt põhiliideseid ja nende rakendusi. Vaatame nende sisu üksikasjalikumalt.

liides IEntityFactoryService ja selle rakendamine EntityFactoryService on andmebaasiga töötamise peamine lähtepunkt, kuna siin luuakse tööühik, konkreetsete olemitega töötamiseks mõeldud hoidlad, aga ka käskude ja otseste SQL-päringute täitjad. Mõnikord on mugav andmebaasiga töötamiseks klassi võimalusi piirata, et võimaldada näiteks ainult andmete lugemist. Sellisteks puhkudeks IEntityFactoryService on olemas esivanem - liides IEntityRepositoryFactory, mis deklareerib ainult hoidlate loomise meetodi.

Andmebaasi otseseks juurdepääsuks kasutatakse pakkuja mehhanismi. Igal DBMS-il, mida me oma meeskondades kasutame, on oma rakendus: ViennaNET.Orm.MSSQL, ViennaNET.Orm.Oracle, ViennaNET.Orm.SQLite, ViennaNET.Orm.PostgreSql.

Samal ajal saab ühes rakenduses registreerida mitu pakkujat korraga, mis võimaldab näiteks ühe teenuse raames ilma infrastruktuuri muutmise kuludeta teostada samm-sammult migratsiooni ühest DBMS-ist teise. Mehhanism konkreetse olemiklassi jaoks ja seega ka pakkuja valimiseks (mille jaoks on kirjutatud vastendamine andmebaasi tabelitesse) realiseeritakse olemi registreerimisega klassis BoundedContext (sisaldab domeeni olemite registreerimise meetodit) või selle järglasesse. ApplicationContext (sisaldab meetodeid rakenduse olemite, otseste päringute ja käskude registreerimiseks), kus argumendina aktsepteeritakse konfiguratsiooni ühenduse identifikaatorit:

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

Näidisrakenduse kontekst:

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

Kui ühenduse ID-d pole määratud, kasutatakse ühendust nimega “vaikimisi”.

Olemite otsene vastendamine andmebaasi tabelitega on realiseeritud standardsete NHibernate'i tööriistade abil. Kirjeldust saate kasutada nii xml-failide kui ka klasside kaudu. Tünnihoidlate mugavaks kirjutamiseks ühiktestides on olemas teek ViennaNET.TestUtils.Orm.

Täielikud näited ViennaNET.Orm.* kasutamisest leiate siin.

ViennaNET.Messaging.*

Teekide komplekt järjekordadega töötamiseks.

Järjekordadega töötamiseks valiti sama lähenemisviis, mis erinevate DBMS-ide puhul, nimelt maksimaalne võimalik ühtne lähenemine teegiga töötamisel, olenemata kasutatavast järjekorrahaldurist. Raamatukogu ViennaNET.Messaging vastutab täpselt selle ühendamise eest ja ViennaNET.Messaging.MQSeriesQueue, ViennaNET.Messaging.RabbitMQQueue и ViennaNET.Messaging.KafkaQueue sisaldavad vastavalt IBM MQ, RabbitMQ ja Kafka adapterite rakendusi.

Järjekordadega töötamisel on kaks protsessi: sõnumi vastuvõtmine ja saatmine.

Kaaluge vastuvõtmist. Siin on 2 võimalust: pidevaks kuulamiseks ja ühe sõnumi vastuvõtmiseks. Järjekorra pidevaks kuulamiseks tuleb esmalt kirjeldada päritud protsessoriklassi IMessageProcessor, mis vastutab sissetuleva sõnumi töötlemise eest. Järgmisena tuleb see "lingida" konkreetse järjekorraga; seda tehakse sisseregistreerimise kaudu IQueueReactorFactory järjekorra identifikaatori näitamine konfiguratsioonist:

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

Näide kuulamise alustamisest:

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

Seejärel, kui teenus käivitub ja kuulamise alustamiseks kutsutakse välja meetod, lähevad kõik määratud järjekorras olevad teated vastavasse protsessorisse.

Ühe sõnumi vastuvõtmiseks tehase liideses IMessagingComponentFactory meetod on olemas CreateMessageReceivermis loob adressaadi, kes ootab talle määratud järjekorrast sõnumit:

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

Sõnumi saatmiseks sa pead sama kasutama IMessagingComponentFactory ja looge sõnumi saatja:

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

Sõnumi serialiseerimiseks ja deserialiseerimiseks on kolm valmis valikut: lihtsalt tekst, XML ja JSON, kuid vajadusel saate hõlpsasti teha oma liidese juurutused IMessageSerializer и IMessageDeserializer.

Oleme püüdnud säilitada iga järjekorrahalduri ainulaadsed võimalused nt. ViennaNET.Messaging.MQSeriesQueue võimaldab saata mitte ainult teksti-, vaid ka baidisõnumeid ja ViennaNET.Messaging.RabbitMQQueue toetab marsruutimist ja järjekorra seadmist. Meie RabbitMQ adapteri ümbris rakendab ka RPC-d: saadame sõnumi ja ootame vastust spetsiaalsest ajutisest järjekorrast, mis luuakse ainult ühe vastusesõnumi jaoks.

siin on järjekordade kasutamise näide põhiliste ühenduse nüanssidega.

ViennaNET.CallContext

Järjekordi kasutame mitte ainult erinevate süsteemide vaheliseks integreerimiseks, vaid ka sama rakenduse mikroteenuste vaheliseks suhtluseks, näiteks saaga raames. See tõi kaasa vajaduse edastada koos sõnumiga sellised abiandmed nagu kasutaja sisselogimine, päringu identifikaator otsast lõpuni logimiseks, lähte-IP-aadress ja autoriseerimisandmed. Nende andmete edastamise rakendamiseks töötasime välja raamatukogu ViennaNET.CallContext, mis võimaldab salvestada teenusesse siseneva päringu andmeid. Sel juhul ei oma tähtsust, kuidas taotlus esitati, kas järjekorra või HTTP kaudu. Seejärel võetakse enne väljamineva päringu või sõnumi saatmist andmed kontekstist ja asetatakse päistesse. Seega saab järgmine teenus abiandmed ja haldab neid samamoodi.

Täname tähelepanu eest, ootame teie kommentaare ja taotlusi!

Allikas: www.habr.com

Lisa kommentaar