ViennaNET: joukko kirjastoja taustajärjestelmää varten. Osa 2

Raiffeisenbank .NET -kehittäjäyhteisö jatkaa lyhyttä ViennaNETin sisällön tarkastelua. Siitä, miten ja miksi päädyimme tähän, voit lukea ensimmäisen osan.

Tässä artikkelissa käymme läpi vielä harkitsemattomia kirjastoja hajautettujen tapahtumien, jonojen ja tietokantojen käsittelyä varten. Ne löytyvät GitHub-arkistosta (lähteet ovat täällä) ja Nuget-paketit täällä.

ViennaNET: joukko kirjastoja taustajärjestelmää varten. Osa 2

ViennaNET.Sagas

Kun projekti siirtyy DDD- ja mikropalveluarkkitehtuuriin, silloin kun liiketoimintalogiikkaa hajautetaan eri palveluihin, syntyy ongelma, joka liittyy tarpeeseen toteuttaa hajautettu tapahtumamekanismi, koska monet skenaariot vaikuttavat usein useisiin toimialueisiin kerralla. Voit tutustua tällaisiin mekanismeihin tarkemmin, esim. kirjassa "Microservices Patterns", Chris Richardson.

Olemme toteuttaneet projekteissamme yksinkertaisen mutta hyödyllisen mekanismin: saagan, tai pikemminkin orkestraatiopohjaisen saagan. Sen olemus on seuraava: on olemassa tietty liiketoimintaskenaario, jossa on tarpeen suorittaa peräkkäisiä operaatioita eri palveluissa, ja jos jossain vaiheessa ilmenee ongelmia, on tarpeen kutsua palautusmenettely kaikille edellisille vaiheille, joissa se on tarjotaan. Siten saagan lopussa saamme onnistumisesta huolimatta johdonmukaisia ​​tietoja kaikilla aloilla.

Toteuksemme on edelleen tehty perusmuodossaan, eikä se ole sidottu minkäänlaisten vuorovaikutustapojen käyttöön muiden palvelujen kanssa. Sitä ei ole vaikea käyttää: tee vain jälkeläinen perusabstraktista SagaBase<T>-luokasta, jossa T on kontekstiluokkasi, johon voit tallentaa saagan toimimiseen tarvittavat alkutiedot sekä joitain välituloksia. Kontekstiesiintymä välitetään kaikkiin vaiheisiin suorituksen aikana. Saga itsessään on tilaton luokka, joten ilmentymä voidaan sijoittaa DI:hen Singletonina tarvittavien riippuvuuksien saamiseksi.

Esimerkkimainos:

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

Esimerkki puhelusta:

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

Voit katsoa täydellisiä esimerkkejä erilaisista toteutuksista täällä ja kokoonpanossa testit.

ViennaNET.Orm.*

Joukko kirjastoja erilaisten tietokantojen työskentelyyn Nhibernaten kautta. Käytämme DB-First-lähestymistapaa Liquibasella, joten käytettävissä on vain toiminnallisuus valmiissa tietokannassa olevien tietojen käsittelyyn.

ViennaNET.Orm.Seedwork и ViennaNET.Orm – perusliitännät sisältävät pääkokoonpanot ja niiden toteutukset. Katsotaanpa niiden sisältöä tarkemmin.

liitäntä IEntityFactoryService ja sen täytäntöönpano EntityFactoryService ovat tärkein lähtökohta tietokannan kanssa työskentelylle, koska työyksikkö, arkistot tiettyjen entiteettien kanssa työskentelyä varten sekä komentojen ja suorien SQL-kyselyjen suorittajat luodaan. Joskus on kätevää rajoittaa luokan mahdollisuuksia työskennellä tietokannan kanssa, esimerkiksi tarjota mahdollisuus vain lukea tietoja. Tällaisiin tapauksiin IEntityFactoryService siellä on esi-isä -rajapinta IEntityRepositoryFactory, joka ilmoittaa vain menetelmän arkistojen luomiseen.

Suoraan tietokantaan pääsemiseksi käytetään palveluntarjoajan mekanismia. Jokaisella tiimeissämme käyttämämme DBMS:llä on oma toteutus: ViennaNET.Orm.MSSQL, ViennaNET.Orm.Oracle, ViennaNET.Orm.SQLite, ViennaNET.Orm.PostgreSql.

Samanaikaisesti yhteen sovellukseen voidaan rekisteröidä useita palveluntarjoajia samanaikaisesti, mikä mahdollistaa esimerkiksi yhden palvelun puitteissa ilman infrastruktuurin muutoskuluja vaiheittaisen siirtymisen DBMS:stä toiseen. Mekanismi vaaditun yhteyden ja siten palveluntarjoajan valitsemiseksi tietylle entiteettiluokalle (jolle kirjoitetaan kartoitus tietokantataulukoihin) toteutetaan rekisteröimällä entiteetti BoundedContext-luokkaan (sisältää menetelmän toimialueen entiteettien rekisteröintiä varten) tai sen seuraajaan. ApplicationContext (sisältää sovelluskokonaisuuksien rekisteröintimenetelmiä, suoria pyyntöjä ja komentoja), jossa konfiguraation yhteystunniste hyväksytään argumentiksi:

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

Esimerkki ApplicationContext:

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

Jos yhteystunnusta ei ole määritetty, käytetään yhteyttä nimeltä "oletus".

Kokonaisuuksien suora kartoitus tietokantataulukoihin on toteutettu NHibernate-standardien työkaluilla. Voit käyttää kuvausta sekä xml-tiedostojen että luokkien kautta. Yksikkötestien tynkävarastojen kirjoittamista varten on kirjasto ViennaNET.TestUtils.Orm.

Täydellisiä esimerkkejä ViennaNET.Orm.*:n käytöstä löytyy täällä.

ViennaNET.Messaging.*

Joukko kirjastoja jonojen kanssa työskentelemiseen.

Jonojen kanssa työskentelyyn valittiin sama lähestymistapa kuin useissa DBMS-järjestelmissä, eli maksimi mahdollinen yhtenäinen lähestymistapa kirjaston kanssa työskentelyssä käytetystä jononhallinnasta riippumatta. Kirjasto ViennaNET.Messaging on juuri vastuussa tästä yhdistymisestä, ja ViennaNET.Messaging.MQSeriesQueue, ViennaNET.Messaging.RabbitMQQueue и ViennaNET.Messaging.KafkaQueue sisältää sovitintoteutuksia IBM MQ:lle, RabbitMQ:lle ja Kafkalle.

Jonojen kanssa työskennellessä on kaksi prosessia: viestin vastaanottaminen ja sen lähettäminen.

Harkitse vastaanottamista. Tässä on kaksi vaihtoehtoa: jatkuva kuuntelu ja yksittäisen viestin vastaanottaminen. Jotta voit kuunnella jatkuvasti jonoa, sinun on ensin kuvattava prosessoriluokka, josta peritty IMessageProcessor, joka vastaa saapuvan viestin käsittelystä. Seuraavaksi se on "linkitettävä" tiettyyn jonoon; tämä tehdään rekisteröitymällä IQueueReactorFactory ilmoittamalla jonon tunnisteen kokoonpanosta:

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

Esimerkki kuuntelun aloittamisesta:

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

Sitten, kun palvelu käynnistyy ja menetelmää kutsutaan aloittamaan kuuntelu, kaikki määritetyn jonon viestit menevät vastaavalle prosessorille.

Yhden viestin vastaanottaminen tehdasliittymässä IMessagingComponentFactory on menetelmä CreateMessageReceiverjoka luo vastaanottajan, joka odottaa viestiä sille määritetystä jonosta:

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

Lähettää viesti sinun täytyy käyttää samaa IMessagingComponentFactory ja luo viestin lähettäjä:

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

Viestin sarjoitukseen ja sarjoitukseen on kolme valmiita vaihtoehtoa: vain teksti, XML ja JSON, mutta tarvittaessa voit helposti tehdä omia käyttöliittymätoteutuksia IMessageSerializer и IMessageDeserializer.

Olemme pyrkineet säilyttämään jokaisen jonopäällikön ainutlaatuiset ominaisuudet, mm. ViennaNET.Messaging.MQSeriesQueue voit lähettää tekstin lisäksi myös tavuviestejä ja ViennaNET.Messaging.RabbitMQQueue tukee reititystä ja lennossa jonotusta. RabbitMQ:n sovitinkääreemme toteuttaa myös jonkinlaisen RPC:n vaikutelman: lähetämme viestin ja odotamme vastausta erityisestä väliaikaisesta jonosta, joka luodaan vain yhdelle vastausviestille.

Täällä esimerkki jonojen käytöstä perusyhteysviiveillä.

ViennaNET.CallContext

Käytämme jonoja eri järjestelmien välisen integroinnin lisäksi myös saman sovelluksen mikropalvelujen väliseen kommunikaatioon esimerkiksi saagan sisällä. Tämä johti tarpeeseen lähettää viestin mukana sellaisia ​​aputietoja kuin käyttäjän kirjautuminen, pyynnön tunniste päästä päähän -lokiin, lähde-IP-osoite ja valtuutustiedot. Näiden tietojen välittämisen toteuttamiseksi kehitimme kirjaston ViennaNET.CallContext, jonka avulla voit tallentaa tietoja palveluun saapuvasta pyynnöstä. Tässä tapauksessa sillä, miten pyyntö tehtiin, jonon kautta tai HTTP:n kautta, ei ole väliä. Sitten ennen lähtevän pyynnön tai viestin lähettämistä data otetaan kontekstista ja sijoitetaan otsikoihin. Siten seuraava palvelu vastaanottaa aputiedot ja hoitaa niitä samalla tavalla.

Kiitos huomiostasi, odotamme kommenttejasi ja vetopyyntöjäsi!

Lähde: will.com

Lisää kommentti