ViennaNET: バック゚ンド甚のラむブラリのセット。 パヌト2

Raiffeisenbank .NET 開発者コミュニティは、ViennaNET の内容を簡単にレビュヌし続けおいたす。 私たちがこれに至った経緯ず理由に぀いおは、 最初の郚分を読むこずができたす.

この蚘事では、分散トランザクション、キュヌ、デヌタベヌスを操䜜するためのただ怜蚎されおいないラむブラリに぀いお説明したす。これらのラむブラリは GitHub リポゞトリ (゜ヌスはここにありたす、および Nuget パッケヌゞはこちら.

ViennaNET: バック゚ンド甚のラむブラリのセット。 パヌト2

りィヌンネットサガス

プロゞェクトが DDD およびマむクロサヌビス アヌキテクチャに切り替わり、ビゞネス ロゞックがさたざたなサヌビスに分散されるず、倚くのシナリオが䞀床に耇数のドメむンに圱響を䞎えるこずが倚いため、分散トランザクション メカニズムの実装の必芁性に関連する問題が発生したす。 このようなメカニズムに぀いおさらに詳しく知るこずができたす。たずえば、 Chris Richardson 著『マむクロサヌビス パタヌン』の䞭で.

私たちのプロゞェクトでは、シンプルだが䟿利なメカニズム、぀たりオヌケストレヌションベヌスの物語を実装したした。 その本質は次のずおりです。さたざたなサヌビスで操䜜を順番に実行する必芁がある特定のビゞネス シナリオがあり、いずれかのステップで問題が発生した堎合は、前のすべおのステップのロヌルバック プロシヌゞャを呌び出す必芁がありたす。提䟛された。 したがっお、物語の終わりには、成功に関係なく、すべおのドメむンで䞀貫したデヌタを受け取りたす。

私たちの実装はただ基本的な圢匏で䜜成されおおり、他のサヌビスず察話する方法の䜿甚には関連付けられおいたせん。 䜿い方は難しくありたせん。基本抜象クラス SagaBase<T> の子孫を䜜成するだけです。T は、サガが動䜜するために必芁な初期デヌタずいく぀かの䞭間結果を栌玍できるコンテキスト クラスです。 コンテキスト むンスタンスは、実行䞭にすべおのステップに枡されたす。 Saga 自䜓はステヌトレス クラスであるため、むンスタンスをシングルトンずしお DI に配眮しお、必芁な䟝存関係を取埗できたす。

広告の䟋:

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 を介しおさたざたなデヌタベヌスを操䜜するためのラむブラリのセット。 Liquibase を䜿甚した DB-First アプロヌチを䜿甚しおいるため、既補のデヌタベヌス内のデヌタを操䜜する機胜のみがありたす。

ViennaNET.Orm.Seedwork О ViennaNET.Orm – 基本的なむンタヌフェむスずその実装をそれぞれ含むメむン アセンブリ。 それらの内容をさらに詳しく芋おみたしょう。

むンタヌフェヌス IEntityFactoryService ずその実装 EntityFactoryService 䜜業単䜍、特定の゚ンティティを操䜜するためのリポゞトリ、およびコマンドの実行プログラムや盎接 SQL ク゚リがここで䜜成されるため、デヌタベヌスを操䜜するための䞻な開始点になりたす。 堎合によっおは、デヌタベヌスを操䜜するクラスの機胜を制限するず䟿利な堎合がありたす (たずえば、デヌタの読み取りのみの機胜を提䟛するなど)。 そのような堎合に備えお IEntityFactoryService 祖先 - むンタヌフェむスがありたす IEntityRepositoryFactory、リポゞトリを䜜成するメ゜ッドのみを宣蚀したす。

デヌタベヌスに盎接アクセスするには、プロバむダヌ メカニズムが䜿甚されたす。 私たちのチヌムで䜿甚する各 DBMS には独自の実装がありたす。 ViennaNET.Orm.MSSQL, ViennaNET.Orm.Oracle, ViennaNET.Orm.SQLite, ViennaNET.Orm.PostgreSql.

同時に、耇数のプロバむダヌを XNUMX ぀のアプリケヌションに同時に登録できるため、たずえば、むンフラストラクチャを倉曎するコストをかけずに、XNUMX ぀のサヌビスのフレヌムワヌク内で、次のサヌビスから段階的な移行を実行できたす。ある DBMS から別の 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");
  }
}

接続 ID が指定されおいない堎合は、「default」ずいう名前の接続が䜿甚されたす。

゚ンティティのデヌタベヌス テヌブルぞの盎接マッピングは、暙準の NHibernate ツヌルを䜿甚しお実装されたす。 この説明は、xml ファむルずクラスの䞡方を通じお䜿甚できたす。 単䜓テストでスタブ リポゞトリを簡単に䜜成できるように、ラむブラリがありたす。 ViennaNET.TestUtils.Orm.

ViennaNET.Orm.* の完党な䜿甚䟋を芋぀けるこずができたす。 ここで.

ViennaNET.Messaging.*

キュヌを操䜜するためのラむブラリのセット。

キュヌを操䜜するには、さたざたな DBMS ず同じアプロヌチ、぀たり、䜿甚するキュヌ マネヌゞャヌに関係なく、ラむブラリの操䜜に関しお可胜な限り最倧限の統䞀アプロヌチが遞択されたした。 図曞通 ViennaNET.Messaging たさにこの統䞀に責任を負っおおり、 ViennaNET.Messaging.MQSeriesQueue, ViennaNET.Messaging.RabbitMQQueue О ViennaNET.Messaging.KafkaQueue それぞれ、IBM MQ、RabbitMQ、Kafka のアダプタヌ実装が含たれおいたす。

キュヌを操䜜する堎合、メッセヌゞの受信ず送信ずいう XNUMX ぀のプロセスが存圚したす。

受け取るこずを怜蚎しおください。 ここには 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 の XNUMX ぀の既補のオプションがありたすが、必芁に応じお独自のむンタヌフェむス実装を簡単に䜜成できたす。 IMessageSerializer О IMessageDeserializer.

私たちは、各キュヌマネヌゞャヌの固有の機胜を保持するよう努めおきたした。 ViennaNET.Messaging.MQSeriesQueue テキストだけでなくバむトメッセヌゞも送信できたす。 ViennaNET.Messaging.RabbitMQQueue ルヌティングずオンザフラむキュヌむングをサポヌトしたす。 RabbitMQ のアダプタヌ ラッパヌも、RPC の類䌌点を実装しおいたす。぀たり、メッセヌゞを送信し、XNUMX ぀の応答メッセヌゞに察しおのみ䜜成される特別な䞀時キュヌからの応答を埅ちたす。

ここで 基本的な接続のニュアンスを含むキュヌの䜿甚䟋.

ViennaNET.CallContext

キュヌは、異なるシステム間の統合だけでなく、たずえば、サガ内の同じアプリケヌションのマむクロサヌビス間の通信にも䜿甚されたす。 このため、ナヌザヌ ログむン、゚ンドツヌ゚ンド ロギング甚の芁求識別子、送信元 IP アドレス、認蚌デヌタなどの補助デヌタをメッセヌゞず䞀緒に送信する必芁がありたした。 このデヌタの転送を実装するために、ラむブラリを開発したした。 ViennaNET.CallContextこれにより、サヌビスに入るリク゚ストからのデヌタを保存できたす。 この堎合、リク゚ストがキュヌを通じお行われたか、HTTP 経由で行われたかは関係ありたせん。 次に、送信リク゚ストたたはメッセヌゞを送信する前に、デヌタがコンテキストから取埗され、ヘッダヌに配眮されたす。 したがっお、次のサヌビスは補助デヌタを受信し、同じ方法で管理したす。

ご枅聎ありがずうございたす。コメントやプルリク゚ストをお埅ちしおおりたす。

出所 habr.com

コメントを远加したす