في هذه المقالة ، سوف نتصفح المكتبات التي لم يتم النظر فيها بعد للعمل مع المعاملات الموزعة وقوائم الانتظار وقواعد البيانات ، والتي يمكن العثور عليها في مستودعنا على GitHub ( المصدر هنا ) ، وحزم Nuget هنا .
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فيها الإعلان فقط عن طريقة إنشاء المستودعات.
للوصول المباشر إلى قاعدة البيانات ، يتم استخدام آلية الموفر. لكل المستخدمة في فرق قاعدة البيانات لدينا التنفيذ الخاصة بها:
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": "..."
}
],
مثال على التطبيق
internal sealed class DbContext : ApplicationContext
{
public DbContext()
{
AddEntity<SomeEntity>("mssql_connection");
AddEntity<MigratedSomeEntity>("oracle_connection");
AddEntity<AnotherEntity>("oracle_connection");
}
}
إذا لم يتم تحديد معرف الاتصال ، فسيتم استخدام الاتصال المسمى "افتراضي".
يتم تنفيذ التعيين المباشر للكيانات إلى جداول قاعدة البيانات باستخدام أدوات NHibernate القياسية. يمكنك استخدام الوصف من خلال ملفات xml ومن خلال الفئات. للحصول على مستودعات أبخرة الكتابة المريحة في اختبارات الوحدة ، توجد مكتبة
ViennaNET.TestUtils.Orm.
يمكن العثور على أمثلة كاملة لاستخدام ViennaNET.Orm. * هنا .
ViennaNET. المراسلة. *
مجموعة من المكتبات للعمل مع قوائم الانتظار.
للعمل مع قوائم الانتظار ، تم اختيار نفس النهج كما هو الحال مع أنظمة إدارة قواعد البيانات المختلفة ، أي أقصى نهج موحد ممكن من حيث العمل مع المكتبة ، بغض النظر عن مدير قائمة الانتظار المستخدم. المكتبة
ViennaNET.Messagingهي المسؤولة فقط عن هذا التوحيد ، ViennaNET.Messaging.MQSeriesQueue, ViennaNET.Messaging.RabbitMQQueue ViennaNET.Messaging.KafkaQueueوتحتوي على تطبيقات المهايئ لـ IBM MQ و RabbitMQ و Kafka على التوالي.
هناك عمليتان في العمل مع قوائم الانتظار: تلقي رسالة وإرسالها.
النظر في الحصول على. يوجد خياران هنا: للاستماع المستمر وتلقي رسالة واحدة. للاستماع إلى قائمة الانتظار باستمرار ، تحتاج أولاً إلى وصف فئة المعالج الموروثة منه
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. بعد ذلك ، قبل إرسال طلب أو رسالة صادرة ، يتم إخراج البيانات من السياق ووضعها في الرؤوس. وبالتالي ، تتلقى الخدمة التالية البيانات المساعدة وتتخلص منها بنفس الطريقة.
شكرا لاهتمامكم ، ونحن نتطلع إلى تعليقاتكم وطلبات السحب!