Raiffeisenbank .NET ծրագրավորողների համայնքը շարունակում է համառոտ ուսումնասիրել ViennaNET-ի բովանդակությունը: Այն մասին, թե ինչպես և ինչու եկանք դրան,
Այս հոդվածում մենք կանցնենք բաշխված գործարքների, հերթերի և տվյալների բազաների հետ աշխատելու համար դեռևս չհամարվող գրադարանների միջոցով, որոնք կարելի է գտնել մեր GitHub պահոցում (
ViennaNET.Sagas
Երբ նախագիծն անցնում է DDD-ի և միկրոսերվիսային ճարտարապետության, ապա երբ բիզնես տրամաբանությունը բաշխվում է տարբեր ծառայություններում, խնդիր է առաջանում՝ կապված բաշխված գործարքների մեխանիզմի ներդրման անհրաժեշտության հետ, քանի որ շատ սցենարներ հաճախ ազդում են միանգամից մի քանի տիրույթների վրա: Նման մեխանիզմներին կարող եք ավելի մանրամասն ծանոթանալ, օրինակ.
Մեր նախագծերում մենք իրականացրել ենք մի պարզ, բայց օգտակար մեխանիզմ՝ սագա, ավելի ճիշտ՝ նվագախմբի վրա հիմնված սագա։ Դրա էությունը հետևյալն է. կա որոշակի բիզնես սցենար, որում անհրաժեշտ է հաջորդաբար գործողություններ կատարել տարբեր ծառայություններում, և եթե որևէ քայլում որևէ խնդիր առաջանա, անհրաժեշտ է կանչել հետադարձ ընթացակարգ բոլոր նախորդ քայլերի համար, որտեղ դա կա. տրամադրվում է. Այսպիսով, սագայի վերջում, անկախ հաջողությունից, մենք ստանում ենք հետևողական տվյալներ բոլոր տիրույթներում։
Մեր ներդրումը դեռևս իրականացվում է իր հիմնական ձևով և կապված չէ այլ ծառայությունների հետ փոխգործակցության որևէ մեթոդի կիրառման հետ: Դժվար չէ օգտագործել. պարզապես ստեղծեք SagaBase<T> բազային վերացական դասի հետնորդը, որտեղ T-ը ձեր համատեքստի դասն է, որտեղ դուք կարող եք պահպանել նախնական տվյալները, որոնք անհրաժեշտ են սագայի աշխատանքի համար, ինչպես նաև որոշ միջանկյալ արդյունքներ: Համատեքստի օրինակը կփոխանցվի կատարման ընթացքում բոլոր քայլերին: Սագան ինքնին քաղաքացիություն չունեցող դաս է, ուստի օրինակը կարող է տեղադրվել DI-ում որպես Singleton՝ անհրաժեշտ կախվածություններ ստանալու համար:
Գովազդի օրինակ.
public class ExampleSaga : SagaBase<ExampleContext>
{
public ExampleSaga()
{
Step("Step 1")
.WithAction(c => ...)
.WithCompensation(c => ...);
AsyncStep("Step 2")
.WithAction(async c => ...);
}
}
Զանգի օրինակ.
var saga = new ExampleSaga();
var context = new ExampleContext();
await saga.Execute(context);
Տարբեր իրականացումների ամբողջական օրինակներ կարող են դիտվել
ViennaNET.Orm.*
Գրադարանների մի շարք Nhibernate-ի միջոցով տարբեր տվյալների բազաների հետ աշխատելու համար: Մենք օգտագործում ենք DB-First մոտեցումը, օգտագործելով Liquibase-ը, այնպես որ կա միայն պատրաստի տվյալների բազայում տվյալների հետ աշխատելու գործառույթ:
ViennaNET.Orm.Seedwork и ViennaNET.Orm
– հիմնական հավաքույթներ, որոնք պարունակում են համապատասխանաբար հիմնական միջերեսներ և դրանց իրականացում: Դիտարկենք դրանց բովանդակությունը ավելի մանրամասն։
ինտերֆեյս IEntityFactoryService
և դրա իրականացումը EntityFactoryService
Տվյալների բազայի հետ աշխատելու հիմնական մեկնարկային կետն է, քանի որ այստեղ ստեղծվում են Աշխատանքի միավորը, հատուկ սուբյեկտների հետ աշխատելու պահոցներ, ինչպես նաև հրամանների կատարողներ և ուղղակի SQL հարցումներ: Երբեմն հարմար է սահմանափակել դասի հնարավորությունները տվյալների բազայի հետ աշխատելու համար, օրինակ՝ ապահովել միայն տվյալների ընթերցման հնարավորությունը։ Նման դեպքերի համար IEntityFactoryService
կա նախնի - ինտերֆեյս IEntityRepositoryFactory
, որը միայն հայտարարում է պահեստներ ստեղծելու մեթոդ։
Տվյալների բազան ուղղակիորեն մուտք գործելու համար օգտագործվում է մատակարարի մեխանիզմը: Յուրաքանչյուր DBMS, որը մենք օգտագործում ենք մեր թիմերում, ունի իր ներդրումը. ViennaNET.Orm.MSSQL, ViennaNET.Orm.Oracle, ViennaNET.Orm.SQLite, ViennaNET.Orm.PostgreSql
.
Միևնույն ժամանակ, մի քանի պրովայդերներ կարող են գրանցվել միաժամանակ մեկ հավելվածում, ինչը թույլ է տալիս, օրինակ, մեկ ծառայության շրջանակներում, առանց ենթակառուցվածքի փոփոխման ծախսերի, իրականացնել քայլ առ քայլ միգրացիա: մեկ DBMS մյուսին: Պահանջվող կապի ընտրության մեխանիզմը և, հետևաբար, մատակարարը որոշակի օբյեկտի դասի համար (որի համար գրված է տվյալների բազայի աղյուսակների քարտեզագրումը) իրականացվում է կազմակերպության գրանցման միջոցով BoundedContext դասում (պարունակում է տիրույթի սուբյեկտների գրանցման մեթոդ) կամ դրա իրավահաջորդը: ApplicationContext (պարունակում է կիրառական սուբյեկտների գրանցման մեթոդներ, ուղղակի հարցումներ և հրամաններ), որտեղ կոնֆիգուրացիայից կապի նույնացուցիչն ընդունվում է որպես փաստարկ.
"db": [
{
"nick": "mssql_connection",
"dbServerType": "MSSQL",
"ConnectionString": "...",
"useCallContext": true
},
{
"nick": "oracle_connection",
"dbServerType": "Oracle",
"ConnectionString": "..."
}
],
Օրինակ ApplicationContext:
internal sealed class DbContext : ApplicationContext
{
public DbContext()
{
AddEntity<SomeEntity>("mssql_connection");
AddEntity<MigratedSomeEntity>("oracle_connection");
AddEntity<AnotherEntity>("oracle_connection");
}
}
Եթե կապի ID-ն նշված չէ, ապա կօգտագործվի «default» անունով կապը:
Սուբյեկտների ուղղակի քարտեզագրումը տվյալների բազայի աղյուսակներին իրականացվում է ստանդարտ NHibernate գործիքների միջոցով: Նկարագրությունը կարող եք օգտագործել ինչպես xml ֆայլերի, այնպես էլ դասերի միջոցով։ Unit-ի թեստերում կոճղերի պահեստները հարմար գրելու համար կա գրադարան ViennaNET.TestUtils.Orm
.
ViennaNET.Orm.*-ի օգտագործման ամբողջական օրինակներ կարելի է գտնել
ViennaNET.Messaging.*
Գրադարանների հավաքածու՝ հերթերի հետ աշխատելու համար:
Հերթերի հետ աշխատելու համար ընտրվել է նույն մոտեցումը, ինչ տարբեր DBMS-ների դեպքում, այն է՝ գրադարանի հետ աշխատելու առավելագույն հնարավոր միասնական մոտեցումը՝ անկախ օգտագործվող հերթի կառավարիչից: Գրադարան ViennaNET.Messaging
հենց այս միավորման պատասխանատուն է, և ViennaNET.Messaging.MQSeriesQueue, ViennaNET.Messaging.RabbitMQQueue и ViennaNET.Messaging.KafkaQueue
պարունակում են համապատասխանաբար IBM MQ, RabbitMQ և Kafka ադապտերների ներդրում:
Հերթերի հետ աշխատելիս երկու գործընթաց կա՝ հաղորդագրություն ստանալը և ուղարկելը։
Մտածեք ստանալը: Այստեղ կա 2 տարբերակ՝ շարունակական լսելու և մեկ հաղորդագրություն ստանալու համար: Հերթին անընդհատ լսելու համար նախ պետք է նկարագրեք ժառանգված պրոցեսորի դասը IMessageProcessor
, որը պատասխանատու կլինի մուտքային հաղորդագրության մշակման համար։ Այնուհետև այն պետք է «կապվի» որոշակի հերթի հետ, դա արվում է գրանցման միջոցով IQueueReactorFactory
նշելով հերթի նույնացուցիչը կազմաձևից.
"messaging": {
"ApplicationName": "MyApplication"
},
"rabbitmq": {
"queues": [
{
"id": "myQueue",
"queuename": "lalala",
...
}
]
},
Լսելը սկսելու օրինակ.
_queueReactorFactory.Register<MyMessageProcessor>("myQueue");
var queueReactor = queueReactorFactory.CreateQueueReactor("myQueue");
queueReactor.StartProcessing();
Այնուհետև, երբ ծառայությունը սկսվի, և մեթոդը կանչվի լսել սկսելու համար, նշված հերթից բոլոր հաղորդագրությունները կգնան համապատասխան պրոցեսոր:
Գործարանային միջերեսում մեկ հաղորդագրություն ստանալու համար IMessagingComponentFactory
կա մեթոդ CreateMessageReceiver
որը կստեղծի հասցեատեր, որը սպասում է հաղորդագրության իրեն նշված հերթից.
using (var receiver = _messagingComponentFactory.CreateMessageReceiver<TestMessage>("myQueue"))
{
var message = receiver.Receive();
}
Հաղորդագրություն ուղարկելու համար դուք պետք է օգտագործեք նույնը IMessagingComponentFactory
և ստեղծել հաղորդագրություն ուղարկող.
using (var sender = _messagingComponentFactory.CreateMessageSender<MyMessage>("myQueue"))
{
sender.SendMessage(new MyMessage { Value = ...});
}
Հաղորդագրությունը սերիալացնելու և ապասերիալիզացնելու երեք պատրաստ տարբերակ կա՝ պարզապես տեքստ, XML և JSON, բայց անհրաժեշտության դեպքում կարող եք հեշտությամբ կատարել ձեր սեփական ինտերֆեյսի իրականացումները: IMessageSerializer и IMessageDeserializer
.
Մենք փորձել ենք պահպանել յուրաքանչյուր հերթի մենեջերի յուրահատուկ հնարավորությունները, օրինակ. ViennaNET.Messaging.MQSeriesQueue
թույլ է տալիս ուղարկել ոչ միայն տեքստային, այլև բայթային հաղորդագրություններ և ViennaNET.Messaging.RabbitMQQueue
աջակցում է երթուղային և թռիչքային հերթագրմանը: RabbitMQ-ի մեր ադապտերների փաթաթանն իրականացնում է նաև RPC-ի որոշակի տեսք. մենք հաղորդագրություն ենք ուղարկում և սպասում ենք պատասխանի հատուկ ժամանակավոր հերթից, որը ստեղծվում է միայն մեկ պատասխան հաղորդագրության համար:
Այստեղ
ViennaNET.CallContext
Մենք օգտագործում ենք հերթեր ոչ միայն տարբեր համակարգերի միջև ինտեգրվելու, այլև նույն հավելվածի միկրոծառայությունների միջև հաղորդակցության համար, օրինակ՝ սագայի շրջանակներում: Սա հանգեցրեց հաղորդագրության հետ միասին այնպիսի օժանդակ տվյալներ փոխանցելու անհրաժեշտությանը, ինչպիսիք են օգտատիրոջ մուտքը, վերջից մինչև վերջ գրանցման հարցումի նույնացուցիչը, աղբյուրի IP հասցեն և թույլտվության տվյալները: Այս տվյալների վերահասցեավորումն իրականացնելու համար մենք մշակեցինք գրադարան ViennaNET.CallContext
, որը թույլ է տալիս պահպանել տվյալներ ծառայություն մուտքագրող հարցումից: Այս դեպքում, թե ինչպես է հարցումն արվել՝ հերթի միջոցով, թե Http-ի միջոցով, նշանակություն չունի։ Այնուհետև, նախքան ելքային հարցումը կամ հաղորդագրությունն ուղարկելը, տվյալները վերցվում են համատեքստից և տեղադրվում վերնագրերում: Այսպիսով, հաջորդ ծառայությունը ստանում է օժանդակ տվյալները և նույն կերպ կառավարում դրանք։
Շնորհակալություն ուշադրության համար, մենք անհամբեր սպասում ենք ձեր մեկնաբանություններին և խնդրանքներին:
Source: www.habr.com