ViennaNET: bibliotekų rinkinys užpakalinei programai. 2 dalis

Raiffeisenbank .NET kūrėjų bendruomenė ir toliau trumpai peržiūri ViennaNET turinį. Apie tai, kaip ir kodėl mes tai padarėme, galite perskaityti pirmąją dalį.

Šiame straipsnyje apžvelgsime dar neapsvarstytas bibliotekas, skirtas dirbti su paskirstytomis operacijomis, eilėmis ir duomenų bazėmis, kurias galite rasti mūsų GitHub saugykloje (šaltiniai yra čia), ir Nuget paketai čia.

ViennaNET: bibliotekų rinkinys užpakalinei programai. 2 dalis

VienaNET.Sagas

Kai projektas pereina prie DDD ir mikropaslaugų architektūros, tada, kai verslo logika paskirstoma po skirtingas paslaugas, iškyla problema, susijusi su poreikiu įdiegti paskirstytą transakcijų mechanizmą, nes daugelis scenarijų dažnai paveikia kelis domenus vienu metu. Su tokiais mechanizmais galite susipažinti išsamiau, pvz. knygoje „Microservices Patterns“, Chrisas Richardsonas.

Savo projektuose įdiegėme paprastą, bet naudingą mechanizmą: sagą, tiksliau – orkestru grįstą sagą. Jo esmė tokia: yra tam tikras verslo scenarijus, kai reikia nuosekliai atlikti operacijas skirtingose ​​tarnybose, o jei kuriame nors žingsnyje iškyla kokių nors problemų, būtina iškviesti atšaukimo procedūrą visiems ankstesniems veiksmams, kur tai daroma. jeigu. Taigi, sakmės pabaigoje, nepaisant sėkmės, gauname nuoseklius duomenis visose srityse.

Mūsų diegimas vis dar yra pagrindinės formos ir nėra susietas su sąveikos su kitomis paslaugomis metodų naudojimu. Tai nėra sudėtinga naudoti: tiesiog sukurkite bazinės abstrakčios klasės SagaBase<T> palikuonį, kur T yra jūsų kontekstinė klasė, kurioje galite saugoti pradinius duomenis, reikalingus sagai veikti, taip pat kai kuriuos tarpinius rezultatus. Kontekstinis egzempliorius bus perduotas visiems vykdymo etapams. Pati „Saga“ yra klasė be būsenos, todėl egzempliorius gali būti įtrauktas į DI kaip „Singleton“, kad gautų reikiamas priklausomybes.

Skelbimo pavyzdys:

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

Skambučio pavyzdys:

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

Galima peržiūrėti pilnus įvairių įgyvendinimų pavyzdžius čia ir surinkime su bandymai.

ViennaNET.Orm.*

Bibliotekų rinkinys, skirtas darbui su įvairiomis duomenų bazėmis per Nhibernate. Mes naudojame DB-First metodą naudodami Liquibase, todėl yra tik funkcionalumas, skirtas dirbti su duomenimis paruoštoje duomenų bazėje.

ViennaNET.Orm.Seedwork и ViennaNET.Orm – pagrindiniai agregatai, kuriuose yra atitinkamai pagrindinės sąsajos ir jų įgyvendinimai. Pažvelkime į jų turinį išsamiau.

sąsaja IEntityFactoryService ir jos įgyvendinimas EntityFactoryService yra pagrindinis atspirties taškas dirbant su duomenų baze, nes čia sukuriamas darbo vienetas, saugyklos darbui su konkrečiais subjektais, taip pat komandų vykdytojai ir tiesioginės SQL užklausos. Kartais patogu apriboti klasės galimybes dirbant su duomenų baze, pavyzdžiui, suteikti galimybę tik skaityti duomenis. Tokiems atvejams IEntityFactoryService yra protėvis – sąsaja IEntityRepositoryFactory, kuris tik deklaruoja saugyklų kūrimo metodą.

Norint tiesiogiai pasiekti duomenų bazę, naudojamas teikėjo mechanizmas. Kiekviena DBVS, kurią naudojame savo komandose, turi savo įgyvendinimą: ViennaNET.Orm.MSSQL, ViennaNET.Orm.Oracle, ViennaNET.Orm.SQLite, ViennaNET.Orm.PostgreSql.

Tuo pačiu metu vienoje programoje vienu metu gali būti registruojami keli teikėjai, o tai leidžia, pavyzdžiui, vienos paslaugos ribose, be jokių infrastruktūros modifikavimo išlaidų, atlikti laipsnišką perėjimą iš viena DBVS į kitą. Reikalingo ryšio, taigi ir konkrečios objekto klasės (kuriai parašytas susiejimas su duomenų bazėmis lentelėmis) parinkimo mechanizmas įgyvendinamas registruojant objektą BoundedContext klasėje (yra domeno objektų registravimo metodas) arba jos įpėdinėje. ApplicationContext (yra taikomų objektų registravimo metodai, tiesioginės užklausos ir komandos), kur ryšio identifikatorius iš konfigūracijos priimamas kaip argumentas:

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

Programos konteksto pavyzdys:

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

Jei ryšio ID nenurodytas, bus naudojamas ryšys, pavadintas „numatytasis“.

Tiesioginis objektų susiejimas su duomenų bazių lentelėmis įgyvendinamas naudojant standartinius NHibernate įrankius. Aprašymą galite naudoti tiek per xml failus, tiek per klases. Norint patogiai rašyti stuburo talpyklas vienetų testuose, yra biblioteka ViennaNET.TestUtils.Orm.

Galima rasti visus ViennaNET.Orm.* naudojimo pavyzdžius čia.

ViennaNET.Messaging.*

Bibliotekų rinkinys darbui su eilėmis.

Darbui su eilėmis buvo pasirinktas toks pat metodas kaip ir su įvairiomis DBVS, ty maksimaliai įmanomas vieningas požiūris dirbant su biblioteka, neatsižvelgiant į naudojamą eilių tvarkyklę. biblioteka ViennaNET.Messaging yra būtent atsakinga už šį susivienijimą ir ViennaNET.Messaging.MQSeriesQueue, ViennaNET.Messaging.RabbitMQQueue и ViennaNET.Messaging.KafkaQueue yra atitinkamai IBM MQ, RabbitMQ ir Kafka adapterio diegimai.

Dirbant su eilėmis, vyksta du procesai: žinutės gavimas ir siuntimas.

Apsvarstykite galimybę gauti. Čia yra 2 pasirinkimai: nuolatiniam klausymuisi ir vieno pranešimo gavimui. Norėdami nuolat klausytis eilės, pirmiausia turite aprašyti procesoriaus klasę, iš kurios buvo paveldėta IMessageProcessor, kuri bus atsakinga už gaunamo pranešimo apdorojimą. Tada jis turi būti „susietas“ su konkrečia eile, tai daroma registruojantis IQueueReactorFactory nurodant eilės identifikatorių iš konfigūracijos:

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

Klausymo pradžios pavyzdys:

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

Tada, kai paslauga paleidžiama ir iškviečiamas metodas pradėti klausytis, visi pranešimai iš nurodytos eilės pateks į atitinkamą procesorių.

Norėdami gauti vieną pranešimą gamyklinėje sąsajoje IMessagingComponentFactory yra metodas CreateMessageReceiverkuris sukurs gavėją, laukiantį pranešimo iš jam nurodytos eilės:

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

Norėdami išsiųsti žinutę jums reikia naudoti tą patį IMessagingComponentFactory ir sukurti pranešimo siuntėją:

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

Yra trys paruoštos pranešimo serijos ir deserializavimo parinktys: tik tekstas, XML ir JSON, bet jei reikia, galite lengvai įdiegti savo sąsają. IMessageSerializer и IMessageDeserializer.

Stengėmės išsaugoti unikalias kiekvieno eilių tvarkytojo galimybes, pvz. ViennaNET.Messaging.MQSeriesQueue leidžia siųsti ne tik tekstinius, bet ir baitinius pranešimus, ir ViennaNET.Messaging.RabbitMQQueue palaiko maršruto parinkimą ir eilių sudarymą skrydžio metu. Mūsų RabbitMQ adapterio įvynioklis taip pat įgyvendina tam tikrą RPC panašumą: mes išsiunčiame pranešimą ir laukiame atsakymo iš specialios laikinos eilės, kuri sukuriama tik vienam atsakymo pranešimui.

Čia eilių naudojimo su pagrindiniais ryšio niuansais pavyzdys.

ViennaNET.CallContext

Eiles naudojame ne tik integracijai tarp skirtingų sistemų, bet ir komunikacijai tarp tos pačios programos mikropaslaugų, pavyzdžiui, sagos viduje. Dėl to reikėjo kartu su pranešimu perduoti tokius pagalbinius duomenis, kaip vartotojo prisijungimo duomenis, užklausos identifikatorių, skirtą tiesioginiam registravimui, šaltinio IP adresą ir autorizacijos duomenis. Siekdami įgyvendinti šių duomenų persiuntimą, sukūrėme biblioteką ViennaNET.CallContext, kuri leidžia saugoti duomenis iš užklausos įvedus paslaugą. Šiuo atveju tai, kaip buvo pateikta užklausa, eilėje ar per Http, neturi reikšmės. Tada, prieš siunčiant siunčiamą užklausą ar pranešimą, duomenys paimami iš konteksto ir dedami į antraštes. Taigi, kita tarnyba gauna pagalbinius duomenis ir tvarko juos taip pat.

Dėkojame už dėmesį, laukiame jūsų komentarų ir užklausų!

Šaltinis: www.habr.com

Добавить комментарий