ViennaNET: aizmugursistēmas bibliotēku komplekts. 2. daļa

Raiffeisenbank .NET izstrādātāju kopiena turpina īsi pārskatīt ViennaNET saturu. Par to, kā un kāpēc mēs nonācām pie tā, jūs varat izlasīt pirmo daļu.

Å ajā rakstā mēs apskatÄ«sim vēl neapsvērtās bibliotēkas darbam ar izplatÄ«tajiem darÄ«jumiem, rindām un datu bāzēm, kuras var atrast mÅ«su GitHub repozitorijā (avoti ir Å”eit) un Nuget paketes Å”eit.

ViennaNET: aizmugursistēmas bibliotēku komplekts. 2. daļa

ViennaNET.Sāgas

Projektam pārejot uz DDD un mikropakalpojumu arhitektÅ«ru, tad, kad biznesa loÄ£ika tiek sadalÄ«ta pa dažādiem servisiem, rodas problēma saistÄ«bā ar nepiecieÅ”amÄ«bu ieviest izkliedētu transakciju mehānismu, jo daudzi scenāriji nereti skar vairākus domēnus vienlaikus. Ar Ŕādiem mehānismiem var iepazÄ«ties sÄ«kāk, piemēram, grāmatā "Microservices Patterns", Kriss Ričardsons.

Savos projektos esam ieviesuÅ”i vienkārÅ”u, bet noderÄ«gu mehānismu: sāgu, pareizāk sakot, uz orÄ·estrāciju balstÄ«tu sāgu. Tās bÅ«tÄ«ba ir Ŕāda: ir noteikts biznesa scenārijs, kurā ir nepiecieÅ”ams secÄ«gi veikt darbÄ«bas dažādos servisos, un, ja kādā solÄ« rodas problēmas, ir nepiecieÅ”ams izsaukt atcelÅ”anas procedÅ«ru visiem iepriekŔējiem soļiem, kur tas ir nodroÅ”ināta. Tādējādi sāgas beigās neatkarÄ«gi no panākumiem mēs saņemam konsekventus datus visās jomās.

MÅ«su ievieÅ”ana joprojām tiek veikta tā pamata formā un nav saistÄ«ta ar mijiedarbÄ«bas ar citiem pakalpojumiem metožu izmantoÅ”anu. To nav grÅ«ti izmantot: vienkārÅ”i izveidojiet pēcteci no pamata abstraktās klases SagaBase<T>, kur T ir jÅ«su konteksta klase, kurā varat saglabāt sākotnējos datus, kas nepiecieÅ”ami sāgas darbÄ«bai, kā arÄ« dažus starprezultātus. Konteksta gadÄ«jums izpildes laikā tiks nodots visām darbÄ«bām. Pati Saga ir bezvalstnieku klase, tāpēc instanci var ievietot DI kā Singleton, lai iegÅ«tu nepiecieÅ”amās atkarÄ«bas.

Reklāmas piemērs:

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

Zvana piemērs:

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

Pilnus dažādu implementāciju piemērus var apskatÄ«t Å”eit un montāžā ar testiem.

ViennaNET.Orm.*

Bibliotēku komplekts darbam ar dažādām datu bāzēm, izmantojot Nhibernate. Mēs izmantojam DB-First pieeju, izmantojot Liquibase, tāpēc ir tikai funkcionalitāte darbam ar datiem gatavā datu bāzē.

ViennaNET.Orm.Seedwork Šø ViennaNET.Orm ā€“ galvenie komplekti, kas satur attiecÄ«gi pamata saskarnes un to realizācijas. ApskatÄ«sim to saturu sÄ«kāk.

interfeiss IEntityFactoryService un tās Ä«stenoÅ”ana EntityFactoryService ir galvenais sākumpunkts darbam ar datu bāzi, jo Å”eit tiek izveidoti darba vienÄ«ba, repozitoriji darbam ar konkrētām entÄ«tijām, kā arÄ« komandu izpildÄ«tāji un tieÅ”ie SQL vaicājumi. Dažkārt ir ērti ierobežot klases iespējas darbam ar datu bāzi, piemēram, lai nodroÅ”inātu iespēju tikai nolasÄ«t datus. Tādiem gadÄ«jumiem IEntityFactoryService ir sencis - interfeiss IEntityRepositoryFactory, kas tikai deklarē repozitoriju izveides metodi.

Lai tieÅ”i piekļūtu datu bāzei, tiek izmantots pakalpojumu sniedzēja mehānisms. Katrai DBVS, ko izmantojam savās komandās, ir sava ievieÅ”ana: ViennaNET.Orm.MSSQL, ViennaNET.Orm.Oracle, ViennaNET.Orm.SQLite, ViennaNET.Orm.PostgreSql.

Vienlaikus vienā aplikācijā var reÄ£istrēt vairākus pakalpojumu sniedzējus vienlaikus, kas ļauj, piemēram, viena pakalpojuma ietvaros bez jebkādām izmaksām par infrastruktÅ«ras pārveidoÅ”anu veikt soli pa solim migrāciju no no vienas DBVS uz citu. Mehānisms vajadzÄ«gā savienojuma un lÄ«dz ar to arÄ« nodroÅ”inātāja izvēlei konkrētai entÄ«tiju klasei (kurai ir rakstÄ«ta kartÄ“Å”ana uz datu bāzes tabulām) tiek Ä«stenots, reÄ£istrējot entÄ«tiju BoundedContext klasē (ietver domēna entÄ«tiju reÄ£istrÄ“Å”anas metodi) vai tās pēcteci. ApplicationContext (satur metodes lietojumprogrammu entÄ«tiju reÄ£istrÄ“Å”anai, tieÅ”os pieprasÄ«jumus un komandas), kur kā arguments tiek pieņemts savienojuma identifikators no konfigurācijas:

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

Lietojumprogrammas konteksta piemērs:

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

Ja savienojuma ID nav norādÄ«ts, tiks izmantots savienojums ar nosaukumu ā€œnoklusējumsā€.

TieÅ”a entÄ«tiju kartÄ“Å”ana datu bāzes tabulām tiek Ä«stenota, izmantojot standarta NHibernate rÄ«kus. Aprakstu var izmantot gan caur xml failiem, gan caur klasēm. Ērtai stub repozitoriju rakstÄ«Å”anai vienÄ«bas testos ir bibliotēka ViennaNET.TestUtils.Orm.

Pilnus ViennaNET.Orm.* izmantoÅ”anas piemērus var atrast Å”eit.

ViennaNET.Ziņapmaiņa.*

Bibliotēku komplekts darbam ar rindām.

Lai strādātu ar rindām, tika izvēlēta tāda pati pieeja kā dažādām DBVS, proti, maksimāli iespējamā vienotā pieeja darbam ar bibliotēku neatkarÄ«gi no izmantotā rindu pārvaldnieka. Bibliotēka ViennaNET.Messaging ir tieÅ”i atbildÄ«gs par Å”o apvienoÅ”anos, un ViennaNET.Messaging.MQSeriesQueue, ViennaNET.Messaging.RabbitMQQueue Šø ViennaNET.Messaging.KafkaQueue satur adaptera implementācijas attiecÄ«gi IBM MQ, RabbitMQ un Kafka.

Strādājot ar rindām, ir divi procesi: ziņojuma saņemÅ”ana un nosÅ«tÄ«Å”ana.

Apsveriet iespēju saņemt. Å eit ir 2 iespējas: nepārtrauktai klausÄ«Å”anai un vienas ziņas saņemÅ”anai. Lai pastāvÄ«gi klausÄ«tos rindu, vispirms jāapraksta procesora klase, kas mantota no IMessageProcessor, kas bÅ«s atbildÄ«gs par ienākoŔā ziņojuma apstrādi. Pēc tam tai jābÅ«t ā€œsaistÄ«taiā€ ar noteiktu rindu; tas tiek darÄ«ts, reÄ£istrējoties IQueueReactorFactory norādot rindas identifikatoru no konfigurācijas:

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

KlausÄ«Å”anās sākÅ”anas piemērs:

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

Pēc tam, kad pakalpojums tiek startēts un tiek izsaukta metode, lai sāktu klausÄ«Å”anos, visi ziņojumi no norādÄ«tās rindas nonāks attiecÄ«gajā procesorā.

Lai saņemtu vienu ziņojumu rūpnīcas saskarnē IMessagingComponentFactory ir metode CreateMessageReceiverkas izveidos adresātu, kas gaida ziņojumu no tam norādītās rindas:

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

Lai nosūtītu ziņu jums ir jāizmanto tas pats IMessagingComponentFactory un izveidojiet ziņojuma sūtītāju:

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

Ziņojuma serializÄ“Å”anai un deserializÄ“Å”anai ir trÄ«s gatavas opcijas: tikai teksts, XML un JSON, bet, ja nepiecieÅ”ams, varat viegli izveidot interfeisa implementācijas. IMessageSerializer Šø IMessageDeserializer.

Esam centuÅ”ies saglabāt katra rindas pārvaldnieka unikālās iespējas, piem. ViennaNET.Messaging.MQSeriesQueue ļauj nosÅ«tÄ«t ne tikai teksta, bet arÄ« baitu ziņas, un ViennaNET.Messaging.RabbitMQQueue atbalsta marÅ”rutÄ“Å”anu un rindu veidoÅ”anu lidojumā. MÅ«su RabbitMQ adaptera iesaiņojums arÄ« ievieÅ” zināmu RPC lÄ«dzÄ«bu: mēs nosÅ«tām ziņojumu un gaidām atbildi no Ä«paÅ”as pagaidu rindas, kas tiek izveidota tikai vienam atbildes ziņojumam.

Å”eit ir rindu izmantoÅ”anas piemērs ar pamata savienojuma niansēm.

ViennaNET.CallContext

Mēs izmantojam rindas ne tikai integrācijai starp dažādām sistēmām, bet arÄ« saziņai starp vienas un tās paÅ”as aplikācijas mikropakalpojumiem, piemēram, sāgas ietvaros. Tas radÄ«ja nepiecieÅ”amÄ«bu kopā ar ziņojumu pārsÅ«tÄ«t tādus papildu datus kā lietotāja pieteikÅ”anās, pieprasÄ«juma identifikators pilnÄ«gai reÄ£istrÄ“Å”anai, avota IP adrese un autorizācijas dati. Lai Ä«stenotu Å”o datu pārsÅ«tÄ«Å”anu, mēs izstrādājām bibliotēku ViennaNET.CallContext, kas ļauj saglabāt datus no pakalpojuma ievadÄ«Å”anas pieprasÄ«juma. Å ajā gadÄ«jumā pieprasÄ«juma iesniegÅ”anas veidam, izmantojot rindu vai HTTP, nav nozÄ«mes. Tad pirms izejoŔā pieprasÄ«juma vai ziņojuma nosÅ«tÄ«Å”anas dati tiek ņemti no konteksta un ievietoti galvenēs. Tādējādi nākamais pakalpojums saņem palÄ«gdatus un pārvalda tos tādā paŔā veidā.

Paldies par uzmanību, gaidīsim jūsu komentārus un pieprasījumus!

Avots: www.habr.com

Pievieno komentāru