ViennaNET: Π½Π°Π±ΠΎΡ€ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ для backend’а. Π§Π°ΡΡ‚ΡŒ 2

БообщСство .NET-Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΎΠ² Π Π°ΠΉΡ„Ρ„Π°ΠΉΠ·Π΅Π½Π±Π°Π½ΠΊΠ° ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠ°Π΅Ρ‚ ΠΊΡ€Π°Ρ‚ΠΊΠΈΠΉ Ρ€Π°Π·Π±ΠΎΡ€ содСрТимого ViennaNET. О Ρ‚ΠΎΠΌ, ΠΊΠ°ΠΊ ΠΈ Π·Π°Ρ‡Π΅ΠΌ ΠΌΡ‹ ΠΊ этому ΠΏΡ€ΠΈΡˆΠ»ΠΈ, ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ Π² ΠΏΠ΅Ρ€Π²ΠΎΠΉ части.

Π’ этой ΡΡ‚Π°Ρ‚ΡŒΠ΅ пройдСмся ΠΏΠΎ Π΅Ρ‰Π΅ Π½Π΅ рассмотрСнным Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°ΠΌ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с распрСдСлСнными транзакциями, очСрСдями ΠΈ Π‘Π”, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΠΎΠΆΠ½ΠΎ Π½Π°ΠΉΡ‚ΠΈ Π² нашСм Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΈ Π½Π° GitHub (исходники Π»Π΅ΠΆΠ°Ρ‚ здСсь), Π° Nuget-ΠΏΠ°ΠΊΠ΅Ρ‚Ρ‹ здСсь.

ViennaNET: Π½Π°Π±ΠΎΡ€ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ для backend’Π°. Π§Π°ΡΡ‚ΡŒ 2

ViennaNET.Sagas

Когда Π² ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π΅ происходит ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ Π½Π° DDD ΠΈ ΠΌΠΈΠΊΡ€ΠΎΡΠ΅Ρ€Π²ΠΈΡΠ½ΡƒΡŽ Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Ρƒ, Ρ‚ΠΎ ΠΏΡ€ΠΈ разнСсСнии бизнСс-Π»ΠΎΠ³ΠΈΠΊΠΈ ΠΏΠΎ Ρ€Π°Π·Π½Ρ‹ΠΌ сСрвисам, Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ‚ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ°, связанная с Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΡΡ‚ΡŒΡŽ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌΠ° распрСдСлСнных Ρ‚Ρ€Π°Π½Π·Π°ΠΊΡ†ΠΈΠΉ, вСдь ΠΌΠ½ΠΎΠ³ΠΈΠ΅ сцСнарии часто Π·Π°Ρ‚Ρ€Π°Π³ΠΈΠ²Π°ΡŽΡ‚ сразу нСсколько Π΄ΠΎΠΌΠ΅Π½ΠΎΠ². Π‘ Ρ‚Π°ΠΊΠΈΠΌΠΈ ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌΠ°ΠΌΠΈ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½Π΅Π΅ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΠ·Π½Π°ΠΊΠΎΠΌΠΈΡ‚ΡŒΡΡ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π² ΠΊΠ½ΠΈΠ³Π΅ Β«Microservices PatternsΒ», Chris Richardson.

Π’ Π½Π°ΡˆΠΈΡ… ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°Ρ… ΠΌΡ‹ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π»ΠΈ простой, Π½ΠΎ ΠΏΠΎΠ»Π΅Π·Π½Ρ‹ΠΉ ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌ: сага, Π° Ρ‚ΠΎΡ‡Π½Π΅Π΅ сага Π½Π° основС оркСстрации. Π‘ΡƒΡ‚ΡŒ Π΅Π΅ Π² ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΌ: Π΅ΡΡ‚ΡŒ Π½Π΅ΠΊΠΈΠΉ бизнСс-сцСнарий, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ ΡΠΎΠ²Π΅Ρ€ΡˆΠΈΡ‚ΡŒ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ Π² Ρ€Π°Π·Π½Ρ‹Ρ… сСрвисах, ΠΏΡ€ΠΈ этом, Π² случаС возникновСния ΠΊΠ°ΠΊΠΈΡ…-Π»ΠΈΠ±ΠΎ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ Π½Π° любом шагС, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ Π²Ρ‹Π·Π²Π°Ρ‚ΡŒ ΠΏΡ€ΠΎΡ†Π΅Π΄ΡƒΡ€Ρƒ ΠΎΡ‚ΠΊΠ°Ρ‚Π° всСх ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰ΠΈΡ… шагов, Π³Π΄Π΅ ΠΎΠ½Π° прСдусмотрСна. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, Π² ΠΊΠΎΠ½Ρ†Π΅ выполнСния саги, нСзависимо ΠΎΡ‚ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎΡΡ‚ΠΈ, ΠΌΡ‹ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ консистСнтныС Π΄Π°Π½Π½Ρ‹Π΅ Π²ΠΎ всСх Π΄ΠΎΠΌΠ΅Π½Π°Ρ….

Наша рСализация ΠΏΠΎΠΊΠ° сдСлана Π² Π±Π°Π·ΠΎΠ²ΠΎΠΌ Π²ΠΈΠ΄Π΅ ΠΈ Π½Π΅ завязана Π½Π° использовании ΠΊΠ°ΠΊΠΈΡ…-Π»ΠΈΠ±ΠΎ способов взаимодСйствия с Π΄Ρ€ΡƒΠ³ΠΈΠΌΠΈ сСрвисами. ΠŸΡ€ΠΈΠΌΠ΅Π½ΡΡ‚ΡŒ Π΅Ρ‘ нСслоТно: достаточно ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ наслСдника ΠΎΡ‚ Π±Π°Π·ΠΎΠ²ΠΎΠ³ΠΎ абстрактного класса SagaBase<Π’>, Π³Π΄Π΅ T – это ваш класс контСкста, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ ΠΌΠΎΠΆΠ½ΠΎ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ исходныС Π΄Π°Π½Π½Ρ‹Π΅, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ саги, Π° Ρ‚Π°ΠΊΠΆΠ΅ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΡ€ΠΎΠΌΠ΅ΠΆΡƒΡ‚ΠΎΡ‡Π½Ρ‹Π΅ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹. ЭкзСмпляр контСкста Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΡ€ΠΎΠ±Ρ€Π°ΡΡ‹Π²Π°Ρ‚ΡŒΡΡ Π²ΠΎ всС шаги Π²ΠΎ врСмя выполнСния. Π‘Π°ΠΌΠ° сага являСтся stateless классом, поэтому экзСмпляр ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ ΠΏΠΎΠΌΠ΅Ρ‰Π΅Π½ Π² 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 ΡΠ²Π»ΡΡŽΡ‚ΡΡ Π³Π»Π°Π²Π½ΠΎΠΉ ΠΎΡ‚ΠΏΡ€Π°Π²Π½ΠΎΠΉ Ρ‚ΠΎΡ‡ΠΊΠΎΠΉ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с Π‘Π”, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ здСсь создаСтся Unit of Work, Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΈ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹ΠΌΠΈ сущностями, Π° Ρ‚Π°ΠΊΠΆΠ΅ исполнитСли ΠΊΠΎΠΌΠ°Π½Π΄ ΠΈ прямых SQL-запросов. Иногда ΡƒΠ΄ΠΎΠ±Π½ΠΎ ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡ΠΈΡ‚ΡŒ возмоТности класса ΠΏΠΎ Ρ€Π°Π±ΠΎΡ‚Π΅ с Π‘Π”, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π΄Π°Ρ‚ΡŒ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для чтСния Π΄Π°Π½Π½Ρ‹Ρ…. Для Ρ‚Π°ΠΊΠΈΡ… случаСв Ρƒ IEntityFactoryService Π΅ΡΡ‚ΡŒ ΠΏΡ€Π΅Π΄ΠΎΠΊ – интСрфСйс IEntityRepositoryFactory, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ объявлСн Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΌΠ΅Ρ‚ΠΎΠ΄ для создания Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠ΅Π².

Для нСпосрСдствСнного обращСния ΠΊ Π‘Π” ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌ ΠΏΡ€ΠΎΠ²Π°ΠΉΠ΄Π΅Ρ€ΠΎΠ². Для ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΠΎΠΉ Ρƒ нас Π² ΠΊΠΎΠΌΠ°Π½Π΄Π°Ρ… Π‘Π£Π‘Π” Π΅ΡΡ‚ΡŒ своя рСализация: ViennaNET.Orm.MSSQL, ViennaNET.Orm.Oracle, ViennaNET.Orm.SQLite, ViennaNET.Orm.PostgreSql.

ΠŸΡ€ΠΈ этом Π² ΠΎΠ΄Π½ΠΎΠΌ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΈ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ зарСгистрировано нСсколько ΠΏΡ€ΠΎΠ²Π°ΠΉΠ΄Π΅Ρ€ΠΎΠ² ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ, Ρ‡Ρ‚ΠΎ позволяСт, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π² Ρ€Π°ΠΌΠΊΠ°Ρ… ΠΎΠ΄Π½ΠΎΠ³ΠΎ сСрвиса Π±Π΅Π· ΠΊΠ°ΠΊΠΈΡ…-Π»ΠΈΠ±ΠΎ Π·Π°Ρ‚Ρ€Π°Ρ‚ Π½Π° Π΄ΠΎΡ€Π°Π±ΠΎΡ‚ΠΊΡƒ инфраструктуры провСсти ΠΏΠΎΡˆΠ°Π³ΠΎΠ²ΡƒΡŽ ΠΌΠΈΠ³Ρ€Π°Ρ†ΠΈΡŽ с ΠΎΠ΄Π½ΠΎΠΉ Π‘Π£Π‘Π” Π½Π° Π΄Ρ€ΡƒΠ³ΡƒΡŽ. ΠœΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌ Π²Ρ‹Π±ΠΎΡ€Π° Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎΠ³ΠΎ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ ΠΈ, ΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ, ΠΏΡ€ΠΎΠ²Π°ΠΉΠ΄Π΅Ρ€Π° для ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠ³ΠΎ класса-сущности (для ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ ΠΈ ΠΏΠΈΡˆΠ΅Ρ‚ΡΡ ΠΌΠ°ΠΏΠΏΠΈΠ½Π³ Π½Π° Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ Π‘Π”) Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½ Ρ‡Π΅Ρ€Π΅Π· Ρ€Π΅Π³ΠΈΡΡ‚Ρ€Π°Ρ†ΠΈΡŽ сущности Π² классС 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");
  }
}

Если ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ Π½Π΅ ΡƒΠΊΠ°Π·Π°Π½, Ρ‚ΠΎ Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ с ΠΈΠΌΠ΅Π½Π΅ΠΌ Β«defaultΒ».

НСпосрСдствСнно ΠΌΠ°ΠΏΠΏΠΈΠ½Π³ сущностСй Π½Π° Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ Π‘Π” рСализуСтся стандартными срСдствами NHibernate. МоТно ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ описаниС ΠΊΠ°ΠΊ Ρ‡Π΅Ρ€Π΅Π· xml-Ρ„Π°ΠΉΠ»Ρ‹, Ρ‚Π°ΠΊ ΠΈ Ρ‡Π΅Ρ€Π΅Π· классы. Для ΡƒΠ΄ΠΎΠ±Π½ΠΎΠ³ΠΎ написания Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠ΅Π²-Π·Π°Π³Π»ΡƒΡˆΠ΅ΠΊ Π² Unit-тСстах, имССтся Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° ViennaNET.TestUtils.Orm.

ΠŸΠΎΠ»Π½ΠΎΡ†Π΅Π½Π½Ρ‹Π΅ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ использования ViennaNET.Orm.* ΠΌΠΎΠΆΠ½ΠΎ Π½Π°ΠΉΡ‚ΠΈ здСсь.

ViennaNET.Messaging.*

Набор Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с очСрСдями.

Для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с очСрСдями Π±Ρ‹Π» Π²Ρ‹Π±Ρ€Π°Π½ Ρ‚Π°ΠΊΠΎΠΉ ΠΆΠ΅ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄, Ρ‡Ρ‚ΠΎ ΠΈ с Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹ΠΌΠΈ Π‘Π£Π‘Π”, Π° ΠΈΠΌΠ΅Π½Π½ΠΎ – максимально Π²ΠΎΠ·ΠΌΠΎΠΆΠ½Ρ‹ΠΉ ΡƒΠ½ΠΈΡ„ΠΈΡ†ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ с Ρ‚ΠΎΡ‡ΠΊΠΈ зрСния Ρ€Π°Π±ΠΎΡ‚Ρ‹ с Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΎΠΉ, нСзависимо ΠΎΡ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΠΎΠ³ΠΎ ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ€Π° ΠΎΡ‡Π΅Ρ€Π΅Π΄Π΅ΠΉ. Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° 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, Π½Π΅ ΠΈΠ³Ρ€Π°Π΅Ρ‚ Ρ€ΠΎΠ»ΠΈ. Π—Π°Ρ‚Π΅ΠΌ, ΠΏΠ΅Ρ€Π΅Π΄ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΠΎΠΉ исходящСго запроса ΠΈΠ»ΠΈ сообщСния, Π΄ΠΎΡΡ‚Π°ΡŽΡ‚ΡΡ Π΄Π°Π½Π½Ρ‹Π΅ ΠΈΠ· контСкста ΠΈ ΠΏΠΎΠΌΠ΅Ρ‰Π°ΡŽΡ‚ΡΡ Π² Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠΈ. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ сСрвис ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅Ρ‚ Π²ΡΠΏΠΎΠΌΠΎΠ³Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅ ΠΈ Π°Π½Π°Π»ΠΎΠ³ΠΈΡ‡Π½ΠΎ ΠΈΠΌΠΈ распоряТаСтся.

Бпасибо Π·Π° Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅, ΠΆΠ΄Ρ‘ΠΌ Π²Π°ΡˆΠΈΡ… ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠ΅Π² ΠΈ pull request-ΠΎΠ²!

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com