{"id":479302,"date":"2026-05-11T10:15:37","date_gmt":"2026-05-11T10:15:37","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=479302"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=479302","title":{"rendered":"\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 MassTransit: \u043a\u0430\u043a \u0443\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041f\u0440\u0438\u0432\u0435\u0442! \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 MassTransit &#8212; \u043e\u0434\u043d\u043e\u0439 \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u0437\u0440\u0435\u043b\u044b\u0445 .NET-\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c, \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0431\u0440\u043e\u043a\u0435\u0440\u0430\u043c\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u043e\u0432 \u0432\u0440\u043e\u0434\u0435 Saga \u0438 Consumer Pipeline.<\/p>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0432\u044b \u043d\u0430\u0447\u043d\u0451\u0442\u0435 \u0447\u0438\u0442\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u044c\u044e, \u0445\u043e\u0447\u0443 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0440\u0435\u043c\u0430\u0440\u043a\u0443: \u044d\u0442\u043e \u043c\u043e\u044f \u043f\u0435\u0440\u0432\u0430\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u044f, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u043e\u0448\u0443 \u043e\u0442\u043d\u0435\u0441\u0442\u0438\u0441\u044c \u0441 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435\u043c. \u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0441\u044f \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0441\u043b\u043e\u0436\u043d\u044b\u043c, \u0430 \u0435\u0433\u043e \u0440\u0430\u0437\u0431\u043e\u0440 \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b.<\/p>\n<p>\u0421\u0442\u0430\u0442\u044c\u044f, \u0432\u0435\u0440\u043e\u044f\u0442\u043d\u043e, \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u043e \u0434\u043e\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0438 \u0443\u0442\u043e\u0447\u043d\u044f\u0442\u044c\u0441\u044f \u043f\u043e \u043c\u0435\u0440\u0435 \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u044b\u0445 \u043f\u0440\u0430\u0432\u043e\u043a. \u0412 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0442\u0430\u043a\u043e\u0433\u043e \u0433\u043b\u0443\u0431\u043e\u043a\u043e\u0433\u043e \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0441\u043a\u043e\u0440\u0435\u0435 \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u043c\u0438 \u0432\u044b\u0432\u043e\u0434\u0430\u043c\u0438, \u043d\u043e \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0431\u044b\u0432\u0430\u0435\u0442 \u043d\u0435\u043f\u0440\u043e\u0441\u0442\u043e \u0441\u0440\u0430\u0437\u0443 \u0438\u0437\u043b\u043e\u0436\u0438\u0442\u044c \u0432\u0441\u0451 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043e. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u043c\u0435\u0441\u0442\u0430\u0445 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u0430 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u0443\u043c\u0431\u0443\u0440\u043d\u043e\u0441\u0442\u044c, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u044f \u043f\u043e\u0441\u0442\u0430\u0440\u0430\u044e\u0441\u044c \u0441\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0435\u043c \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c.<\/p>\n<p>\u0411\u044b\u0441\u0442\u0440\u044b\u0435 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044b<\/p>\n<ul>\n<li>\n<p><a href=\"#mt1\" rel=\"noopener noreferrer nofollow\">\u041f\u043e\u0447\u0435\u043c\u0443 MassTransit \u0431\u044b\u0432\u0430\u0435\u0442 \u0441\u043b\u043e\u0436\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u044c<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#mt2\" rel=\"noopener noreferrer nofollow\">\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0440\u0438\u0447\u0438\u043d\u044b \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#mt3\" rel=\"noopener noreferrer nofollow\">\u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u0430\u044f \u0438\u0434\u0435\u044f: Pipeline<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#mt4\" rel=\"noopener noreferrer nofollow\">GreenPipes \u0441\u0442\u0440\u043e\u0438\u0442\u0441\u044f \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u0445<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#mt5\" rel=\"noopener noreferrer nofollow\">\u041f\u0435\u0440\u0435\u0445\u043e\u0434 \u043a \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0435 MassTransit<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#mt6\" rel=\"noopener noreferrer nofollow\">\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 DI-\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0432 MassTransit<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#mt7\" rel=\"noopener noreferrer nofollow\">\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f MassTransit: \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f vs \u0440\u0443\u0447\u043d\u0430\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#mt8\" rel=\"noopener noreferrer nofollow\">Configuration \u0438 Configurators<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#mt9\" rel=\"noopener noreferrer nofollow\">Runtime-\u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 MassTransit<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#mt10\" rel=\"noopener noreferrer nofollow\">\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438 \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#mt11\" rel=\"noopener noreferrer nofollow\">Pipeline \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 MassTransit<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#mt12\" rel=\"noopener noreferrer nofollow\">ChannelExecutor<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#mt13\" rel=\"noopener noreferrer nofollow\">Pipeline \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 MassTransit<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#mt14\" rel=\"noopener noreferrer nofollow\">Sagas<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#mt15\" rel=\"noopener noreferrer nofollow\">SagaStateMachine \u0438 FSM<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#mt16\" rel=\"noopener noreferrer nofollow\">Sagas \u0432\u043d\u0443\u0442\u0440\u0438 MassTransit<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#mt17\" rel=\"noopener noreferrer nofollow\">SagaStateMachine<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#mt18\" rel=\"noopener noreferrer nofollow\">States \u0432 SagaStateMachine<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#mt19\" rel=\"noopener noreferrer nofollow\">SagaStateMachine \u0438 Graphs<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#mt20\" rel=\"noopener noreferrer nofollow\">\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 Sagas<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#mt21\" rel=\"noopener noreferrer nofollow\">\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#mt22\" rel=\"noopener noreferrer nofollow\">\u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044c Saga \u043a\u0430\u043a \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#mt23\" rel=\"noopener noreferrer nofollow\">\u041b\u0443\u0447\u0448\u0438\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 Sagas Orchestration<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#mt24\" rel=\"noopener noreferrer nofollow\">\u041f\u0440\u0438\u043c\u0435\u0440 \u043d\u0430 NServiceBus<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#mt25\" rel=\"noopener noreferrer nofollow\">\u041a\u0430\u043a\u043e\u0439 \u0432\u044b\u0432\u043e\u0434 \u043a\u0430\u0441\u0430\u0435\u043c\u043e Sagas?<\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"#mt26\" rel=\"noopener noreferrer nofollow\">\u041f\u043e\u0434\u0432\u0435\u0434\u0435\u043c \u0438\u0442\u043e\u0433\u0438<\/a><\/p>\n<\/li>\n<\/ul>\n<p>\u0415\u0441\u043b\u0438 \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u0431\u043e\u043b\u0435\u0435 \u0433\u043b\u0443\u0431\u043e\u043a\u043e\u0433\u043e \u0440\u0430\u0437\u0431\u043e\u0440\u0430 \u0441 \u043a\u043e\u0434\u043e\u043c \u0438 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0435\u0439 \u043f\u043e \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0430\u043c, \u0443 \u043c\u0435\u043d\u044f \u0435\u0441\u0442\u044c \u0438 <a href=\"https:\/\/www.youtube.com\/watch?v=egnkAEsIBr8&amp;t\" rel=\"noopener noreferrer nofollow\">\u0432\u0438\u0434\u0435\u043e\u0440\u0430\u0437\u0431\u043e\u0440 \u043d\u0430 YouTube<\/a>. \u0417\u0434\u0435\u0441\u044c \u0436\u0435 &#8212; \u043a\u0440\u0430\u0442\u043a\u0430\u044f, \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u0434\u043b\u044f \u0442\u0435\u0445, \u043a\u0442\u043e \u0445\u043e\u0447\u0435\u0442 \u043f\u043e\u043d\u044f\u0442\u044c \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u044b\u0435 \u0438\u0434\u0435\u0438 \u0431\u0435\u0437 \u043f\u043e\u0433\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0432 50+ \u043c\u0438\u043d\u0443\u0442 \u0432\u0438\u0434\u0435\u043e.<\/p>\n<p><a class=\"anchor\" name=\"mt1\" id=\"mt1\"><\/a><\/p>\n<h3>\u041f\u043e\u0447\u0435\u043c\u0443 MassTransit \u0431\u044b\u0432\u0430\u0435\u0442 \u0441\u043b\u043e\u0436\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u044c<\/h3>\n<p>MassTransit \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0443\u0436\u0435 \u0431\u043e\u043b\u0435\u0435 15 \u043b\u0435\u0442. \u042d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043b\u0430\u0441\u044c \u0435\u0449\u0451 \u0432\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0430 \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e .NET Framework &#8212; \u0437\u0430\u0434\u043e\u043b\u0433\u043e \u0434\u043e \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044f CoreCLR \u0438 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0433\u043e .NET.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/8PGopQd.jpeg\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/8PGopQd.jpeg 780w,&#10;       https:\/\/i.imgur.com\/8PGopQd.jpeg 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p>\u0410\u0432\u0442\u043e\u0440 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 &#8212; Chris Patterson, Microsoft MVP \u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043b MassTransit \u043a\u0430\u043a \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 abstraction layer \u043d\u0430\u0434 \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u0430\u043c\u0438 (RabbitMQ, Azure Service Bus, Amazon SQS \u0438 \u0434\u0440.).<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/dTOY6RM.jpeg\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/dTOY6RM.jpeg 780w,&#10;       https:\/\/i.imgur.com\/dTOY6RM.jpeg 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p>\u041f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u0437\u043d\u0430\u043a\u043e\u043c\u0441\u0442\u0432\u0435 \u043a\u043e\u0434\u043e\u0432\u0430\u044f \u0431\u0430\u0437\u0430 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u043f\u0435\u0440\u0435\u0433\u0440\u0443\u0436\u0435\u043d\u043d\u043e\u0439. \u041d\u043e \u043f\u0440\u0438\u0447\u0438\u043d\u0430 \u043d\u0435 \u0432 \u0432\u043e\u0437\u0440\u0430\u0441\u0442\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0430 \u0432 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u043e\u0439 \u043d\u0430\u0441\u044b\u0449\u0435\u043d\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p><a class=\"anchor\" name=\"mt2\" id=\"mt2\"><\/a><\/p>\n<h3>\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0440\u0438\u0447\u0438\u043d\u044b \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438 :<\/h3>\n<ol>\n<li>\n<p>\u0411\u043e\u043b\u044c\u0448\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u043e\u0432 MassTransit \u0430\u043a\u0442\u0438\u0432\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442: Pipeline, Observer, Visitor, State, Finite State Machine(FSM) \u0438 \u0442\u0434\u2026 \u0422\u043e \u0435\u0441\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 &#8212; \u044d\u0442\u043e \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u201c\u043e\u0431\u0451\u0440\u0442\u043a\u0430 \u043d\u0430\u0434 RabbitMQ\u201d, \u0430 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 framework \u0441 \u0431\u043e\u0433\u0430\u0442\u043e\u0439 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0439 \u043c\u043e\u0434\u0435\u043b\u044c\u044e.<\/p>\n<\/li>\n<li>\n<p>\u0413\u043b\u0443\u0431\u043e\u043a\u043e\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 generics \u041f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u0441\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0441\u0442\u0440\u043e\u0438\u0442\u0441\u044f \u0432\u043e\u043a\u0440\u0443\u0433 T:<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"cs\">ConsumeContext&lt;T&gt;ConsumerConsumeContext&lt;TConsumer, TMessage&gt;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:87px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<ol start=\"3\">\n<li>\n<p>\u0422\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u043d\u043e-\u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u043d\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 MassTransit \u0441\u0442\u0430\u0440\u0430\u0435\u0442\u0441\u044f \u0431\u044b\u0442\u044c \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u043c, \u043d\u043e \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u0430 \u0432\u0441\u0451 \u0440\u0430\u0432\u043d\u043e \u043f\u0440\u043e\u043d\u0438\u043a\u0430\u044e\u0442 \u0432\u043d\u0443\u0442\u0440\u044c \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b.<\/p>\n<\/li>\n<\/ol>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 RabbitMQ:<\/p>\n<ul>\n<li>\n<p>\u043e\u0434\u043d\u043e TCP-\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e channels;<\/p>\n<\/li>\n<li>\n<p>channels \u043d\u0435\u043b\u044c\u0437\u044f \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e \u0431\u0435\u0437 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f;<\/p>\n<\/li>\n<li>\n<p>\u043a\u043b\u0438\u0435\u043d\u0442 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0430\u043a\u043a\u0443\u0440\u0430\u0442\u043d\u043e\u0433\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f concurrency, \u0438\u043d\u0430\u0447\u0435 \u043c\u043e\u0436\u043d\u043e \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u0442\u044c\u0441\u044f \u0441 \u043d\u0430\u0440\u0443\u0448\u0435\u043d\u0438\u0435\u043c AMQP framing.<\/p>\n<\/li>\n<\/ul>\n<p>\u0418\u043c\u0435\u043d\u043d\u043e \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 RabbitMQ Transport \u0435\u0441\u0442\u044c \u0442\u0430\u043a\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043a\u0430\u043a ChannelExecutor, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u0432\u044b\u0433\u043b\u044f\u0434\u044f\u0442 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u043c\u0438: \u043e\u043d\u0438 \u043f\u043e\u043c\u043e\u0433\u0430\u044e\u0442 \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c channel \u0438 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0442\u0430\u043c, \u0433\u0434\u0435 \u044d\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e<\/p>\n<ol start=\"4\">\n<li>\n<p>SagaStateMachine \u0438 \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u044b\u0435 \u0433\u0440\u0430\u0444\u044b \u041a\u043e\u0433\u0434\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0432\u043f\u0435\u0440\u0432\u044b\u0435 \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442 SagaStateMachine, \u0433\u0440\u0430\u0444\u044b \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u043e\u0432 \u043c\u043e\u0433\u0443\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043a\u0430\u043a \u0447\u0430\u0441\u0442\u044c runtime-\u043c\u0430\u0433\u0438\u0438.<\/p>\n<\/li>\n<\/ol>\n<p>\u041d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u044d\u0442\u043e \u0441\u043a\u043e\u0440\u0435\u0435 \u0434\u0435\u043a\u043b\u0430\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442:<\/p>\n<ul>\n<li>\n<p>\u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f<\/p>\n<\/li>\n<li>\n<p>\u0441\u043e\u0431\u044b\u0442\u0438\u044f<\/p>\n<\/li>\n<li>\n<p>\u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044b<\/p>\n<\/li>\n<\/ul>\n<p>\u0413\u0440\u0430\u0444\u044b \u043d\u0443\u0436\u043d\u044b \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u0434\u043b\u044f \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u0430\u043d\u0430\u043b\u0438\u0437\u0430, \u0430 \u043d\u0435 \u043a\u0430\u043a \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 runtime-\u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f.<\/p>\n<pre><code class=\"cs\">[HttpGet(\"graph\/edges\")]    public IActionResult GetGraphEdges()    {        var graph = _machine.GetGraph();        var sb = new StringBuilder();        sb.AppendLine(\"stateDiagram-v2\");        foreach (var edge in graph.Edges)        {            var from = edge.From.Title;            var to = edge.To.Title;            sb.AppendLine($\"{from} --&gt; {to}\");        }        return Content(sb.ToString(), \"text\/plain\");    }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<pre><code class=\"cs\">[HttpGet(\"graph\/vertices\")]    public IActionResult GetGraphVertices()    {        var graph = _machine.GetGraph();        var sb = new StringBuilder();        sb.AppendLine(\"stateDiagram-v2\");        foreach (var vertex in graph.Vertices)        {            sb.AppendLine($\"state {vertex.Title}\");        }        return Content(sb.ToString(), \"text\/plain\");    }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><a class=\"anchor\" name=\"mt3\" id=\"mt3\"><\/a><\/p>\n<h3>\u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u0430\u044f \u0438\u0434\u0435\u044f: Pipeline<\/h3>\n<p>MassTransit \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0441\u0442\u0440\u043e\u0438\u043b\u0441\u044f \u043f\u043e\u0432\u0435\u0440\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 GreenPipes, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u043b\u0430 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u044e\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443 Pipeline. \u0412 \u043d\u043e\u0432\u044b\u0445 \u0432\u0435\u0440\u0441\u0438\u044f\u0445 MassTransit GreenPipes \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043a\u0430\u043a \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0430\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c &#8212; \u0435\u0451 \u043a\u043e\u0434 \u0431\u044b\u043b \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u043d \u0432 \u0441\u0430\u043c MassTransit. \u042d\u0442\u043e \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u043e \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e GreenPipes \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0430 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0437\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u043c\u0438 \u044d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u044b MassTransit, \u0430 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043d\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u043b\u0438 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<p>\u041d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u0432 \u043e\u0441\u043d\u043e\u0432\u0435 MassTransit \u043b\u0435\u0436\u0438\u0442 \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u044b\u0439 \u043f\u0430\u0442\u0442\u0435\u0440\u043d Pipes &amp; Filters, \u043d\u043e \u044d\u0442\u043e \u043d\u0435 \u0441\u043e\u0432\u0441\u0435\u043c \u0442\u0430\u043a.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/hWRncr8.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/hWRncr8.png 780w,&#10;       https:\/\/i.imgur.com\/hWRncr8.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p>\u041a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0439 Pipes &amp; Filters \u0445\u043e\u0440\u043e\u0448\u043e \u0437\u043d\u0430\u043a\u043e\u043c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u043e Bash-\u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440\u0430\u043c, \u0433\u0434\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0440\u0430\u0431\u043e\u0442\u044b \u043e\u0434\u043d\u043e\u0439 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0447\u0435\u0440\u0435\u0437 \u0441\u0438\u043c\u0432\u043e\u043b |:<\/p>\n<pre><code class=\"bash\">cat file.txt | grep \"error\" | sort | uniq<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043a\u0430\u0436\u0434\u0430\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u0435\u0442 \u043a\u0430\u043a Filter, \u0430 Pipe \u0441\u043b\u0443\u0436\u0438\u0442 \u043b\u0438\u0448\u044c \u043a\u0430\u043d\u0430\u043b\u043e\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u0435\u0436\u0434\u0443 \u044d\u0442\u0430\u043f\u0430\u043c\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438.<\/p>\n<p>\u0412 MassTransit \u043c\u043e\u0434\u0435\u043b\u044c \u0441\u043b\u043e\u0436\u043d\u0435\u0435. \u0425\u043e\u0442\u044f \u0442\u0435\u0440\u043c\u0438\u043d\u043e\u043b\u043e\u0433\u0438\u044f Pipes \u0438 Filters \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f, \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0431\u043b\u0438\u0436\u0435 \u043a Middleware Pipeline, \u0447\u0435\u043c \u043a \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u043e\u043c\u0443 Pipes &amp; Filters. \u0426\u0435\u043f\u043e\u0447\u043a\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043a\u0430\u043a \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c Pipe -&gt; Filter -&gt; Pipe -&gt; Filter, \u043e\u0434\u043d\u0430\u043a\u043e \u043a\u0430\u0436\u0434\u044b\u0439 Filter \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442 \u0435\u0433\u043e \u0434\u0430\u043b\u044c\u0448\u0435, \u0430 \u043c\u043e\u0436\u0435\u0442:<\/p>\n<ol>\n<li>\n<p>\u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0438\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435\u043c \u0446\u0435\u043f\u043e\u0447\u043a\u0438<\/p>\n<\/li>\n<li>\n<p>\u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438<\/p>\n<\/li>\n<li>\n<p>\u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0432\u0435\u0442\u0432\u043b\u0435\u043d\u0438\u044f<\/p>\n<\/li>\n<li>\n<p>\u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435<\/p>\n<\/li>\n<li>\n<p>\u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 Pipes<\/p>\n<\/li>\n<\/ol>\n<p>\u0422\u043e \u0435\u0441\u0442\u044c Filter \u0437\u0434\u0435\u0441\u044c \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u0435\u0442 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u043c, \u043d\u043e \u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u043c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0442\u043e\u043a\u043e\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f (Control Flow), \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 MassTransit \u0431\u043b\u0438\u0436\u0435 \u043a middleware-\u043f\u043e\u0434\u0445\u043e\u0434\u0443, \u0433\u0434\u0435 \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u0443\u0435\u0442, \u043a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0448\u0430\u0433. \u0418\u043c\u0435\u043d\u043d\u043e \u043f\u043e\u044d\u0442\u043e\u043c\u0443 Pipeline \u0432 MassTransit &#8212; \u044d\u0442\u043e \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043b\u0438\u043d\u0435\u0439\u043d\u0430\u044f \u0446\u0435\u043f\u043e\u0447\u043a\u0430 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432, \u0430 \u0431\u043e\u043b\u0435\u0435 \u0433\u0438\u0431\u043a\u0430\u044f \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u0430\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439.<\/p>\n<p>\u041e\u0442\u0441\u044e\u0434\u0430 \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0437\u044e\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u043a\u0430\u043a Pipes &amp; Filter \u0441 Middleware Control Flow<\/p>\n<p><a class=\"anchor\" name=\"mt4\" id=\"mt4\"><\/a><\/p>\n<h3>GreenPipes \u0441\u0442\u0440\u043e\u0438\u0442\u0441\u044f \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u0445<\/h3>\n<ul>\n<li>\n<p>Agents &#8212;  \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u043c \u0446\u0438\u043a\u043b\u043e\u043c \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0412 \u0447\u0430\u0441\u0442\u044c \u0438\u0445 \u043e\u0431\u044f\u0437\u0430\u043d\u043d\u043e\u0441\u0442\u0435\u0439 \u0432\u0445\u043e\u0434\u0438\u0442: \u0441\u0442\u0430\u0440\u0442, \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0433\u043e\u0442\u043e\u0432\u043d\u043e\u0441\u0442\u0438, \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0430\u0445 \u0412 \u043f\u0440\u0438\u043c\u0435\u0440 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 RabbitMqBasicConsumer, \u0447\u0442\u043e \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f Agent\u2019\u043e\u043c, \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043a\u0440\u0443\u0442\u0438\u0442\u0441\u044f \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u044b\u0439 loop \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u0417\u0434\u0435\u0441\u044c \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d \u043c\u0435\u0442\u043e\u0434 HandleBasicDeliver \u0438\u0437 rabbitmq.client<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"cs\">public class RabbitMqBasicConsumer :        Agent,        IAsyncBasicConsumer,        IBasicConsumer,        RabbitMqDeliveryMetrics    {        readonly RabbitMqReceiveEndpointContext _context;        readonly TaskCompletionSource&lt;bool&gt; _deliveryComplete;        readonly IReceivePipeDispatcher _dispatcher;        readonly SemaphoreSlim _limit;        readonly ModelContext _model;        readonly ConcurrentDictionary&lt;ulong, RabbitMqReceiveContext&gt; _pending;        readonly ReceiveSettings _receiveSettings;        string _consumerTag;        EventHandler&lt;ConsumerEventArgs&gt; _onConsumerCancelled;        \/\/\/ &lt;summary&gt;        \/\/\/ The basic consumer receives messages pushed from the broker.        \/\/\/ &lt;\/summary&gt;        \/\/\/ &lt;param name=\"model\"&gt;The model context for the consumer&lt;\/param&gt;        \/\/\/ &lt;param name=\"context\"&gt;The topology&lt;\/param&gt;        public RabbitMqBasicConsumer(ModelContext model, RabbitMqReceiveEndpointContext context)        {            _model = model;            _context = context;            _receiveSettings = model.GetPayload&lt;ReceiveSettings&gt;();            _pending = new ConcurrentDictionary&lt;ulong, RabbitMqReceiveContext&gt;();            _dispatcher = context.CreateReceivePipeDispatcher();            _dispatcher.ZeroActivity += HandleDeliveryComplete;            _deliveryComplete = TaskUtil.GetTask&lt;bool&gt;();            if (context.ConcurrentMessageLimit.HasValue)                _limit = new SemaphoreSlim(context.ConcurrentMessageLimit.Value);            ConsumerCancelled += OnConsumerCancelled;        }...        Task IAsyncBasicConsumer.HandleBasicDeliver(string consumerTag, ulong deliveryTag, bool redelivered, string exchange, string routingKey,            IBasicProperties properties, ReadOnlyMemory&lt;byte&gt; body)        {            HandleBasicDeliver(consumerTag, deliveryTag, redelivered, exchange, routingKey, properties, body);            return Task.CompletedTask;        }public void HandleBasicDeliver(string consumerTag, ulong deliveryTag, bool redelivered, string exchange, string routingKey,            IBasicProperties properties, ReadOnlyMemory&lt;byte&gt; body)        {            var bodyBytes = body.ToArray();            Task.Run(async () =&gt;            {                LogContext.Current = _context.LogContext;                var context = new RabbitMqReceiveContext(exchange, routingKey, _consumerTag, deliveryTag, bodyBytes, redelivered, properties,                    _context, _receiveSettings, _model, _model.ConnectionContext);                var added = _pending.TryAdd(deliveryTag, context);                if (!added &amp;&amp; deliveryTag != 1) \/\/ DIRECT REPLY-TO fixed value                    LogContext.Warning?.Log(\"Duplicate BasicDeliver: {DeliveryTag}\", deliveryTag);                var receiveLock = _receiveSettings.NoAck ? default : new RabbitMqReceiveLockContext(_model, deliveryTag);                if (_limit != null)                    await _limit.WaitAsync(context.CancellationToken).ConfigureAwait(false);                try                {                    await _dispatcher.Dispatch(context, receiveLock).ConfigureAwait(false);                }                catch (Exception exception)                {                    context.LogTransportFaulted(exception);                }                finally                {                    _limit?.Release();                    if (added)                        _pending.TryRemove(deliveryTag, out _);                    context.Dispose();                }            });        }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<ul>\n<li>\n<p>Supervisors &#8212; \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u0442\u0438\u043f Agent\u2019\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 Agent\u2019\u0430\u043c\u0438. \u041f\u043e \u0441\u0443\u0442\u0438, \u044d\u0442\u043e \u201cagent of agents\u201d \u0438\u043b\u0438 \u043e\u0440\u043a\u0435\u0441\u0442\u0440\u0430\u0442\u043e\u0440 \u0430\u0433\u0435\u043d\u0442\u043e\u0432, \u043d\u043e \u044d\u0442\u043e \u043d\u0435 \u0432\u0441\u0435, \u0432\u0435\u0434\u044c \u043e\u043d \u043c\u043e\u0436\u0435\u0442 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0434\u0440\u0443\u0433\u0438\u043c\u0438 supervisors. Supervisor \u0445\u0440\u0430\u043d\u0438\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0445 Agent\u2019\u043e\u0432, \u0441\u0442\u0430\u0440\u0442\u0443\u0435\u0442 \u0438\u0445 \u043f\u0440\u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u043f\u0440\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438.<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"cs\">    public class TransportPipeContextSupervisor&lt;T&gt; :        PipeContextSupervisor&lt;T&gt;,        ITransportSupervisor&lt;T&gt;        where T : class, PipeContext    {        readonly ISupervisor _consumeSupervisor;        readonly ISupervisor _sendSupervisor;        protected TransportPipeContextSupervisor(IPipeContextFactory&lt;T&gt; factory)            : base(factory)        {            _consumeSupervisor = new Supervisor();            _sendSupervisor = new Supervisor();        }        public void Probe(ProbeContext context)        {            if (HasContext)                context.Add(\"connected\", true);        }        public void AddSendAgent&lt;TAgent&gt;(TAgent agent)            where TAgent : IAgent        {            _sendSupervisor.Add(agent);        }        public void AddConsumeAgent&lt;TAgent&gt;(TAgent agent)            where TAgent : IAgent        {            _consumeSupervisor.Add(agent);        }        protected override async Task StopSupervisor(StopSupervisorContext context)        {            await _consumeSupervisor.Stop(context).ConfigureAwait(false);            await _sendSupervisor.Stop(context).ConfigureAwait(false);            await base.StopSupervisor(context).ConfigureAwait(false);        }    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<ul>\n<li>\n<p>Probe \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0434\u0438\u0430\u0433\u043d\u043e\u0441\u0442\u0438\u043a\u0438 \u0438 \u0441\u0430\u043c\u043e\u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f pipeline. \u0413\u0434\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f:<\/p>\n<\/li>\n<\/ul>\n<ol>\n<li>\n<p>\u0414\u0438\u0430\u0433\u043d\u043e\u0441\u0442\u0438\u043a\u0430 \u041f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 pipeline \u0438 \u0435\u0433\u043e \u0441\u043e\u0441\u0442\u0430\u0432.<\/p>\n<\/li>\n<li>\n<p>Monitoring \/ Observability \u0414\u0430\u0451\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, circuit breaker, \u043f\u043e\u043f\u044b\u0442\u043a\u0438, \u043e\u0448\u0438\u0431\u043a\u0438).<\/p>\n<\/li>\n<li>\n<p>\u041e\u0442\u043b\u0430\u0434\u043a\u0430 \u041f\u043e\u043c\u043e\u0433\u0430\u0435\u0442 \u043f\u043e\u043d\u044f\u0442\u044c, \u043f\u043e\u0447\u0435\u043c\u0443 \u0444\u0438\u043b\u044c\u0442\u0440 \u043d\u0435 \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0438\u043b\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043d\u0435 \u0442\u0430\u043a, \u043a\u0430\u043a \u043e\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044f.<\/p>\n<\/li>\n<li>\n<p>\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u041c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430\u0440\u0443\u0436\u0443 &#8212; \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 \u043c\u0435\u0442\u0440\u0438\u043a\u0438 \u0438\u043b\u0438 \u0434\u0438\u0430\u0433\u043d\u043e\u0441\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 endpoints.<\/p>\n<\/li>\n<li>\n<p>\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u041f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0438\u0441\u0430\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u0442\u043e\u0447\u043d\u044b\u0435 \u0442\u0435\u0441\u0442\u044b: [1] \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c, \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u044b\u0435 \u0444\u0438\u043b\u044c\u0442\u0440\u044b \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u044b [2]  \u0432\u0430\u043b\u0438\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0440\u044f\u0434\u043e\u043a pipeline [3]  \u0443\u0431\u0435\u0436\u0434\u0430\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0430 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e [4] \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0431\u0435\u0437 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u043e\u043b\u043d\u043e\u0433\u043e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"cs\">public class PipeContextSupervisor&lt;TContext&gt; :        Supervisor,        ISupervisor&lt;TContext&gt;        where TContext : class, PipeContext    {        readonly ISupervisor _activeSupervisor;        readonly IPipeContextFactory&lt;TContext&gt; _contextFactory;        readonly object _contextLock = new object();        PipeContextHandle&lt;TContext&gt; _context;        \/\/\/ &lt;summary&gt;        \/\/\/ Create the cache        \/\/\/ &lt;\/summary&gt;        \/\/\/ &lt;param name=\"contextFactory\"&gt;Factory used to create the underlying and active contexts&lt;\/param&gt;        public PipeContextSupervisor(IPipeContextFactory&lt;TContext&gt; contextFactory)        {            _contextFactory = contextFactory;            _activeSupervisor = new Supervisor();        }        protected bool HasContext        {            get            {                lock (_contextLock)                {                    return _context is { IsDisposed: false };                }            }        }        void IProbeSite.Probe(ProbeContext context)        {            var scope = context.CreateScope(\"source\");            scope.Set(new            {                Type = TypeCache&lt;PipeContextSupervisor&lt;TContext&gt;&gt;.ShortName,                HasContext,            });        }...}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<pre><code class=\"cs\"> [Test]        public void Should_override_bus_setting_if_specified()        {            var busControl = MassTransit.Bus.Factory.CreateUsingActiveMq(cfg =&gt;            {                cfg.PrefetchCount = 427;                cfg.ReceiveEndpoint(\"input-queue\", e =&gt;                {                    e.PrefetchCount = 351;                });            });            var jsonString = busControl.GetProbeResult().ToJsonString();            var probe = JObject.Parse(jsonString);            Assert.That(GetPrefetchCount(probe, 0), Is.EqualTo(351));            Assert.That(GetPrefetchCount(probe, 1), Is.EqualTo(427));        }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<ul>\n<li>\n<p>Pipes &#8212; \u0433\u043e\u0442\u043e\u0432\u044b\u0435, \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0438 \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u044b\u0435 \u0446\u0435\u043f\u043e\u0447\u043a\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u042d\u0442\u043e execution layer pipeline, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043b\u043e\u0433\u0438\u043a\u0438 \u0432\u043e \u0432\u0440\u0435\u043c\u044f runtime\u2019\u0430. \u041e\u043d \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0446\u0435\u043f\u043e\u0447\u043a\u0443 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0432 \u0435\u0434\u0438\u043d\u0443\u044e \u0440\u0430\u0431\u043e\u0447\u0443\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443. FilterPipe, EmtyPipe \u044d\u0442\u043e \u043e\u0434\u043d\u0438 \u0438\u0437 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0430 by default pipes<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"cs\">public class FilterPipe&lt;TContext&gt; :        IPipe&lt;TContext&gt;        where TContext : class, PipeContext    {        readonly IFilter&lt;TContext&gt; _filter;        readonly IPipe&lt;TContext&gt; _next;        public FilterPipe(IFilter&lt;TContext&gt; filter, IPipe&lt;TContext&gt; next)        {            _filter = filter;            _next = next;        }        public void Probe(ProbeContext context)        {            _filter.Probe(context);            _next.Probe(context);        }        [DebuggerStepThrough]        public Task Send(TContext context)        {            return _filter.Send(context, _next);        }    }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<pre><code class=\"cs\">public class EmptyPipe&lt;TContext&gt; :        IPipe&lt;TContext&gt;        where TContext : class, PipeContext    {        [DebuggerNonUserCode]        Task IPipe&lt;TContext&gt;.Send(TContext context)        {            return Task.CompletedTask;        }        void IProbeSite.Probe(ProbeContext context)        {        }    }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<ul>\n<li>\n<p>Filters \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u043c pipeline (middleware), \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435 Send. \u0424\u0438\u043b\u044c\u0442\u0440\u044b \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0441\u043e\u0431\u043e\u0439 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0435 \u044d\u0442\u0430\u043f\u044b \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0432 \u0446\u0435\u043f\u043e\u0447\u043a\u0435 (Pipe), \u0433\u0434\u0435 \u043a\u0430\u0436\u0434\u044b\u0439 Filter \u043c\u043e\u0436\u0435\u0442 \u043c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442, \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0443 \u0438\u043b\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043f\u043e\u0431\u043e\u0447\u043d\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438. \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 Filter\u2019\u0430 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0443 middleware \u0438 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0442\u0440\u0435\u0445 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0444\u0430\u0437:<\/p>\n<\/li>\n<\/ul>\n<ol>\n<li>\n<p>\u0424\u0430\u0437\u0430 1: \u0414\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 (DoSomething)<\/p>\n<\/li>\n<li>\n<p>\u0424\u0430\u0437\u0430 2: \u041f\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f (next.Send)<\/p>\n<\/li>\n<li>\n<p>\u0424\u0430\u0437\u0430 3: \u041f\u043e\u0441\u043b\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 (DoSomethingAfter)<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"cs\">public class TransportReadyFilter&lt;T&gt; :        IFilter&lt;T&gt;        where T : class, PipeContext    {        readonly ReceiveEndpointContext _context;        public TransportReadyFilter(ReceiveEndpointContext context)        {            _context = context;        }        public async Task Send(T context, IPipe&lt;T&gt; next)        {            \/\/ \u041f\u0435\u0440\u0432\u0430\u044f \u0444\u0430\u0437\u0430            await _context.TransportObservers.NotifyReady(_context.InputAddress).ConfigureAwait(false);            var agent = new Agent();            agent.SetReady();            _context.AddConsumeAgent(agent);            \/\/ \u0412\u0442\u043e\u0440\u0430\u044f \u0444\u0430\u0437\u0430            await next.Send(context).ConfigureAwait(false);            \/\/ \u0422\u0440\u0435\u0442\u044c\u044f \u0424\u0430\u0437\u0430            await agent.Completed.ConfigureAwait(false);        }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<ul>\n<li>\n<p>Context \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0438 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u043c \u0446\u0438\u043a\u043b\u043e\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0432\u043d\u0443\u0442\u0440\u0438 Pipeline. Pipeline &#8212; \u044d\u0442\u043e \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u0434\u0432\u0438\u0436\u0435\u0442\u0441\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430. Context &#8212; \u044d\u0442\u043e \u201c\u043f\u043e\u0441\u044b\u043b\u043a\u0430\u201d, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0435\u0434\u0435\u0442 \u043f\u043e \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440\u0443 \u043e\u0442 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u0430\u043d\u0446\u0438\u0438 \u043a \u0434\u0440\u0443\u0433\u043e\u0439. Filters &#8212; \u044d\u0442\u043e \u0441\u0442\u0430\u043d\u0446\u0438\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u041a\u0430\u0436\u0434\u044b\u0439 Filter \u0431\u0435\u0440\u0435\u0442 Context, \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0441\u0432\u043e\u044e \u0440\u0430\u0431\u043e\u0442\u0443, \u043c\u043e\u0436\u0435\u0442 \u043c\u043e\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c Context \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442 \u0435\u0433\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c\u0443 Filter\u2019\u0443.<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"cs\"> public interface ConsumeContext :        PipeContext,        MessageContext,        IPublishEndpoint,        ISendEndpointProvider    {        \/\/\/ &lt;summary&gt;        \/\/\/ The received message context        \/\/\/ &lt;\/summary&gt;        ReceiveContext ReceiveContext { get; }        \/\/\/ &lt;summary&gt;        \/\/\/ The serializer context from message deserialization        \/\/\/ &lt;\/summary&gt;        SerializerContext SerializerContext { get; }        \/\/\/ &lt;summary&gt;        \/\/\/ An awaitable task that is completed once the consume context is completed        \/\/\/ &lt;\/summary&gt;        Task ConsumeCompleted { get; }        \/\/\/ &lt;summary&gt;        \/\/\/ Returns the supported message types from the message        \/\/\/ &lt;\/summary&gt;        IEnumerable&lt;string&gt; SupportedMessageTypes { get; }        \/\/\/ &lt;summary&gt;        \/\/\/ Returns true if the specified message type is contained in the serialized message        \/\/\/ &lt;\/summary&gt;        \/\/\/ &lt;param name=\"messageType\"&gt;&lt;\/param&gt;        \/\/\/ &lt;returns&gt;&lt;\/returns&gt;        bool HasMessageType(Type messageType);....}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<ul>\n<li>\n<p>Payloads \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0441\u043f\u043e\u0441\u043e\u0431 \u043f\u0440\u0438\u043a\u0440\u0435\u043f\u043b\u044f\u0442\u044c \u043a Context\u2019\u0443 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u043b\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u044b (\u0442\u043e \u0435\u0441\u0442\u044c \u201c\u043f\u043e\u043b\u0435\u0437\u043d\u0443\u044e \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0443\u201d), \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043f\u0443\u0442\u0435\u0448\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u043d\u0438\u043c \u043f\u043e \u0432\u0441\u0435\u043c\u0443 Pipeline \u0438 \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0434\u043b\u044f \u0432\u0441\u0435\u0445 Filter\u2019\u043e\u0432.<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"cs\">public class TransactionFilter&lt;T&gt; :        IFilter&lt;T&gt;        where T : class, PipeContext    {        readonly TransactionOptions _options;        public TransactionFilter(IsolationLevel isolationLevel = IsolationLevel.ReadCommitted, TimeSpan timeout = default)        {            if (timeout == default)                timeout = TimeSpan.FromSeconds(30);            _options = new TransactionOptions            {                IsolationLevel = isolationLevel,                Timeout = timeout            };        }        void IProbeSite.Probe(ProbeContext context)        {            var step = context.CreateFilterScope(\"transaction\");            step.Add(\"isolationLevel\", _options.IsolationLevel.ToString());            step.Add(\"timeout\", _options.Timeout);        }        [DebuggerNonUserCode]        public async Task Send(T context, IPipe&lt;T&gt; next)        {            SystemTransactionContext systemTransactionContext = null;            context.GetOrAddPayload&lt;TransactionContext&gt;(() =&gt;            {                systemTransactionContext = new SystemTransactionContext(_options);                return systemTransactionContext;            });            try            {                await next.Send(context).ConfigureAwait(false);                if (systemTransactionContext != null)                    await systemTransactionContext.Commit().ConfigureAwait(false);            }            catch (Exception ex)            {                systemTransactionContext?.Rollback(ex);                throw;            }            finally            {                systemTransactionContext?.Dispose();            }        }    }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<ul>\n<li>\n<p>Configurators \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u044f\u0437\u044b\u043a \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u044f pipeline. \u042d\u0442\u043e \u0443\u0434\u043e\u0431\u043d\u044b\u0439 API, \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442, \u043a\u0430\u043a \u0434\u043e\u043b\u0436\u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u041a\u043e\u0433\u0434\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430 \u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0441\u0442\u0430\u0440\u0442\u0443\u0435\u0442, Configurators \u0438\u0441\u0447\u0435\u0437\u0430\u044e\u0442 \u0441\u043e \u0441\u0446\u0435\u043d\u044b. \u0418\u0445 \u043c\u0435\u0441\u0442\u043e \u0437\u0430\u043d\u0438\u043c\u0430\u044e\u0442 Agent\u2019\u044b, Supervisor\u2019\u044b, Pipe\u2019\u044b \u0438 Filter\u2019\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442 \u0440\u0435\u0430\u043b\u044c\u043d\u0443\u044e \u0440\u0430\u0431\u043e\u0442\u0443.<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"cs\">public class RabbitMqBusFactoryConfigurator :        BusFactoryConfigurator,        IRabbitMqBusFactoryConfigurator,        IBusFactory    {        readonly IRabbitMqBusConfiguration _busConfiguration;        readonly IRabbitMqHostConfiguration _hostConfiguration;        readonly RabbitMqReceiveSettings _settings;        public RabbitMqBusFactoryConfigurator(IRabbitMqBusConfiguration busConfiguration)            : base(busConfiguration)        {            _busConfiguration = busConfiguration;            _hostConfiguration = busConfiguration.HostConfiguration;            var queueName = busConfiguration.Topology.Consume.CreateTemporaryQueueName(\"bus\");            var exchangeType = busConfiguration.BusEndpointConfiguration.Topology.Consume.ExchangeTypeSelector.DefaultExchangeType;            _settings = new RabbitMqReceiveSettings(busConfiguration.BusEndpointConfiguration, queueName, exchangeType, false, true);            _settings.AutoDeleteAfter(TimeSpan.FromMinutes(1));        }        public IReceiveEndpointConfiguration CreateBusEndpointConfiguration(Action&lt;IReceiveEndpointConfigurator&gt; configure)        {            return _busConfiguration.HostConfiguration.CreateReceiveEndpointConfiguration(_settings, _busConfiguration.BusEndpointConfiguration, configure);        }        public override IEnumerable&lt;ValidationResult&gt; Validate()        {            foreach (var result in base.Validate())                yield return result;            if (string.IsNullOrWhiteSpace(_settings.QueueName))                yield return this.Failure(\"Bus\", \"The bus queue name must not be null or empty\");        }... }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<ul>\n<li>\n<p>Specification \u0441\u043b\u0443\u0436\u0438\u0442 \u043c\u043e\u0441\u0442\u043e\u043c \u043c\u0435\u0436\u0434\u0443 \u044d\u0442\u0430\u043f\u043e\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0438 runtime\u2019\u043e\u043c \u0441\u0438\u0441\u0442\u0435\u043c\u044b, \u043f\u043e \u0441\u0443\u0442\u0438 \u044f\u0432\u043b\u044f\u044f\u0441\u044c \u201c\u0435\u0434\u0438\u043d\u0438\u0446\u043e\u0439 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u044f pipeline\u201d, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b. \u041a\u0430\u0436\u0434\u0430\u044f Specification \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u043e\u0434\u043d\u0443 \u0437\u0430\u0434\u0430\u0447\u0443: \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0444\u0438\u043b\u044c\u0442\u0440\u0430 \u0432 pipeline \u0438\u043b\u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0431\u0440\u043e\u043a\u0435\u0440\u0430<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"cs\">class ConsumerMessageConfigurator :            IConsumerMessageConfigurator&lt;Batch&lt;TMessage&gt;&gt;        {            readonly IBuildPipeConfigurator&lt;ConsumeContext&lt;Batch&lt;TMessage&gt;&gt;&gt; _batchConfigurator;            public ConsumerMessageConfigurator(IBuildPipeConfigurator&lt;ConsumeContext&lt;Batch&lt;TMessage&gt;&gt;&gt; batchConfigurator)            {                _batchConfigurator = batchConfigurator;            }            public void AddPipeSpecification(IPipeSpecification&lt;ConsumeContext&lt;Batch&lt;TMessage&gt;&gt;&gt; specification)            {                _batchConfigurator.AddPipeSpecification(specification);            }        }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<pre><code class=\"cs\">public class PipeConfigurator&lt;TContext&gt; :        IBuildPipeConfigurator&lt;TContext&gt;        where TContext : class, PipeContext    {        readonly List&lt;IPipeSpecification&lt;TContext&gt;&gt; _specifications;        public PipeConfigurator()        {            _specifications = new List&lt;IPipeSpecification&lt;TContext&gt;&gt;(4);        }        public IEnumerable&lt;ValidationResult&gt; Validate()        {            return _specifications.Count == 0                ? Array.Empty&lt;ValidationResult&gt;()                : _specifications.SelectMany(x =&gt; x.Validate());        }        void IPipeConfigurator&lt;TContext&gt;.AddPipeSpecification(IPipeSpecification&lt;TContext&gt; specification)        {            if (specification == null)                throw new ArgumentNullException(nameof(specification));            _specifications.Add(specification);        }        public IPipe&lt;TContext&gt; Build()        {            if (_specifications.Count == 0)                return Pipe.Empty&lt;TContext&gt;();            var builder = new PipeBuilder&lt;TContext&gt;(_specifications.Count);            var count = _specifications.Count;            for (var index = 0; index &lt; count; index++)                _specifications[index].Apply(builder);            return builder.Build();        }    }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<pre><code class=\"cs\">public class ConsumerConsumeContextRescuePipeSpecification&lt;T&gt; :        ExceptionSpecification,        IPipeSpecification&lt;ConsumerConsumeContext&lt;T&gt;&gt;        where T : class    {        readonly IPipe&lt;ExceptionConsumerConsumeContext&lt;T&gt;&gt; _rescuePipe;        public ConsumerConsumeContextRescuePipeSpecification(IPipe&lt;ExceptionConsumerConsumeContext&lt;T&gt;&gt; rescuePipe)        {            _rescuePipe = rescuePipe;        }        public void Apply(IPipeBuilder&lt;ConsumerConsumeContext&lt;T&gt;&gt; builder)        {            builder.AddFilter(new RescueFilter&lt;ConsumerConsumeContext&lt;T&gt;, ExceptionConsumerConsumeContext&lt;T&gt;&gt;(_rescuePipe, Filter,                (context, ex) =&gt; new RescueExceptionConsumerConsumeContext&lt;T&gt;(context, ex)));        }        public IEnumerable&lt;ValidationResult&gt; Validate()        {            if (_rescuePipe == null)                yield return this.Failure(\"RescuePipe\", \"must not be null\");        }    }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<ul>\n<li>\n<p>Validators \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043b\u043e\u0439 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 pipeline \u0434\u043e \u0435\u0433\u043e \u0441\u0431\u043e\u0440\u043a\u0438 \u0432 GreenPipes \u0438 MassTransit. \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u043d\u0435 runtime, \u0430 \u0442\u043e, \u043c\u043e\u0436\u043d\u043e \u043b\u0438 \u0432\u043e\u043e\u0431\u0449\u0435 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u0441\u043e\u0431\u0440\u0430\u0442\u044c pipeline.<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"cs\"> public class ConsumerFilterSpecification&lt;TConsumer, TMessage&gt; :        IPipeSpecification&lt;ConsumerConsumeContext&lt;TConsumer, TMessage&gt;&gt;        where TConsumer : class        where TMessage : class    {        readonly IFilter&lt;ConsumerConsumeContext&lt;TConsumer, TMessage&gt;&gt; _filter;        public ConsumerFilterSpecification(IFilter&lt;ConsumerConsumeContext&lt;TConsumer&gt;&gt; filter)        {            _filter = new ConsumerSplitFilter&lt;TConsumer, TMessage&gt;(filter);        }        public void Apply(IPipeBuilder&lt;ConsumerConsumeContext&lt;TConsumer, TMessage&gt;&gt; builder)        {            builder.AddFilter(_filter);        }        public IEnumerable&lt;ValidationResult&gt; Validate()        {            if (_filter == null)                yield return this.Failure(\"Filter\", \"must not be null\");        }    }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<ul>\n<li>\n<p>Observers &#8212; \u0441\u0438\u0441\u0442\u0435\u043c\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u0438 \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 pipeline \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f. Observer \u201c\u0441\u043b\u0443\u0448\u0430\u0435\u0442\u201d \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0438 \u0440\u0435\u0430\u0433\u0438\u0440\u0443\u0435\u0442 \u043d\u0430 \u043d\u0438\u0445, \u043d\u0435 \u0432\u043b\u0438\u044f\u044f \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043f\u043e\u0442\u043e\u043a \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f Pipeline \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f, \u043d\u043e \u0438 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u044f:<\/p>\n<\/li>\n<\/ul>\n<ol>\n<li>\n<p>\u0444\u0438\u043b\u044c\u0442\u0440 \u043d\u0430\u0447\u0430\u043b \u0440\u0430\u0431\u043e\u0442\u0443<\/p>\n<\/li>\n<li>\n<p>\u0444\u0438\u043b\u044c\u0442\u0440 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043b\u0441\u044f<\/p>\n<\/li>\n<li>\n<p>\u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430<\/p>\n<\/li>\n<li>\n<p>retry \u043d\u0430\u0447\u0430\u043b\u0441\u044f \/ \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043b\u0441\u044f<\/p>\n<\/li>\n<\/ol>\n<p>Connectable &#8212; \u044d\u0442\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0443 Observer\u2019\u043e\u0432 \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432. \u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442, \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0449\u0438\u0439 IConnectable, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c Observer\u2019\u043e\u0432 \u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u044f\u0442\u044c \u0438\u0445 \u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f\u0445.<\/p>\n<p>\u041f\u043e \u0441\u0443\u0442\u0438, Connectable &#8212; \u044d\u0442\u043e \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u0442 Observer\u2019\u043e\u0432 \u0441 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043c\u0438 pipeline\u2019\u0430, \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0443 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0432\u0441\u0435\u043c \u0437\u0430\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u044f\u043c.<\/p>\n<pre><code class=\"cs\">public class Connectable&lt;T&gt;        where T : class    {        readonly Dictionary&lt;long, T&gt; _connections;        T[] _connected;        long _nextId;        public Connectable()        {            _connections = new Dictionary&lt;long, T&gt;();            _connected = Array.Empty&lt;T&gt;();        }        \/\/\/ &lt;summary&gt;        \/\/\/ The number of connections        \/\/\/ &lt;\/summary&gt;        public int Count =&gt; _connected.Length;        \/\/\/ &lt;summary&gt;        \/\/\/ Connect a connectable type        \/\/\/ &lt;\/summary&gt;        \/\/\/ &lt;param name=\"connection\"&gt;The connection to add&lt;\/param&gt;        \/\/\/ &lt;returns&gt;The connection handle&lt;\/returns&gt;        public ConnectHandle Connect(T connection)        {            if (connection == null)                throw new ArgumentNullException(nameof(connection));            var id = Interlocked.Increment(ref _nextId);            lock (_connections)            {                _connections.Add(id, connection);                _connected = _connections.Values.ToArray();            }            return new Handle(id, this);        }        \/\/\/ &lt;summary&gt;        \/\/\/ Enumerate the connections invoking the callback for each connection        \/\/\/ &lt;\/summary&gt;        \/\/\/ &lt;param name=\"callback\"&gt;The callback&lt;\/param&gt;        \/\/\/ &lt;returns&gt;An awaitable Task for the operation&lt;\/returns&gt;        public Task ForEachAsync(Func&lt;T, Task&gt; callback)        {            if (callback == null)                throw new ArgumentNullException(nameof(callback));            T[] connected;            lock (_connections)                connected = _connected;            if (connected.Length == 0)                return Task.CompletedTask;            if (connected.Length == 1)                return callback(connected[0]);            var outputTasks = new Task[connected.Length];            int i;            for (i = 0; i &lt; connected.Length; i++)                outputTasks[i] = callback(connected[i]);            for (i = 0; i &lt; outputTasks.Length; i++)            {                if (outputTasks[i].Status != TaskStatus.RanToCompletion)                    break;            }            if (i == outputTasks.Length)                return Task.CompletedTask;            return Task.WhenAll(outputTasks);        }        public void ForEach(Action&lt;T&gt; callback)        {            T[] connected;            lock (_connections)                connected = _connected;            switch (connected.Length)            {                case 0:                    break;                case 1:                    callback(connected[0]);                    break;                default:                    {                        for (var i = 0; i &lt; connected.Length; i++)                            callback(connected[i]);                        break;                    }            }        }        public bool All(Func&lt;T, bool&gt; callback)        {            T[] connected;            lock (_connections)                connected = _connected;            if (connected.Length == 0)                return true;            if (connected.Length == 1)                return callback(connected[0]);            for (var i = 0; i &lt; connected.Length; i++)            {                if (callback(connected[i]) == false)                    return false;            }            return true;        }        void Disconnect(long id)        {            lock (_connections)            {                _connections.Remove(id);                _connected = _connections.Values.ToArray();            }        }        class Handle :            ConnectHandle        {            readonly Connectable&lt;T&gt; _connectable;            readonly long _id;            public Handle(long id, Connectable&lt;T&gt; connectable)            {                _id = id;                _connectable = connectable;            }            public void Disconnect()            {                _connectable.Disconnect(_id);            }            public void Dispose()            {                Disconnect();            }        }    }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<pre><code class=\"cs\">public class ReceiveObservable :        Connectable&lt;IReceiveObserver&gt;,        IReceiveObserver    {        public Task PreReceive(ReceiveContext context)        {            return ForEachAsync(x =&gt; x.PreReceive(context));        }        public Task PostReceive(ReceiveContext context)        {            return ForEachAsync(x =&gt; x.PostReceive(context));        }        public Task PostConsume&lt;T&gt;(ConsumeContext&lt;T&gt; context, TimeSpan duration, string consumerType)            where T : class        {            return ForEachAsync(x =&gt; x.PostConsume(context, duration, consumerType));        }        public Task ConsumeFault&lt;T&gt;(ConsumeContext&lt;T&gt; context, TimeSpan duration, string consumerType, Exception exception)            where T : class        {            return ForEachAsync(x =&gt; x.ConsumeFault(context, duration, consumerType, exception));        }        public Task ReceiveFault(ReceiveContext context, Exception exception)        {            return ForEachAsync(x =&gt; x.ReceiveFault(context, exception));        }    }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<pre><code class=\"cs\">ublic class PerformanceCounterReceiveObserver :        IReceiveObserver    {        readonly ICounterFactory _factory;        public PerformanceCounterReceiveObserver(ICounterFactory factory)        {            _factory = factory;        }        Task IReceiveObserver.PreReceive(ReceiveContext context)        {            return Task.CompletedTask;        }        Task IReceiveObserver.PostReceive(ReceiveContext context)        {            return Task.CompletedTask;        }        Task IReceiveObserver.PostConsume&lt;T&gt;(ConsumeContext&lt;T&gt; context, TimeSpan duration, string consumerType)        {            ConsumerPerformanceCounterCache.GetCounter(_factory, consumerType).Consumed(duration);            MessagePerformanceCounterCache&lt;T&gt;.Counter(_factory).Consumed(duration);            return Task.CompletedTask;        }        Task IReceiveObserver.ConsumeFault&lt;T&gt;(ConsumeContext&lt;T&gt; context, TimeSpan duration, string consumerType, Exception exception)        {            ConsumerPerformanceCounterCache.GetCounter(_factory, consumerType).Faulted();            MessagePerformanceCounterCache&lt;T&gt;.Counter(_factory).ConsumeFaulted(duration);            return Task.CompletedTask;        }        Task IReceiveObserver.ReceiveFault(ReceiveContext context, Exception exception)        {            return Task.CompletedTask;        }    }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><a class=\"anchor\" name=\"mt5\" id=\"mt5\"><\/a><\/p>\n<h3>\u041f\u0435\u0440\u0435\u0445\u043e\u0434 \u043a \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0435 MassTransit<\/h3>\n<p>\u041c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u044b, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u0442\u0440\u043e\u0438\u0442\u0441\u044f pipeline \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 GreenPipes. \u0422\u0435\u043f\u0435\u0440\u044c \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c, \u043a\u0430\u043a \u044d\u0442\u0438 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0432\u043d\u0443\u0442\u0440\u0438 MassTransit \u0438 \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u044e\u0442 \u0435\u0433\u043e \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439.<\/p>\n<p>\u0420\u0430\u0437\u0431\u043e\u0440 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0447\u0438\u043d\u0430\u0442\u044c\u0441\u044f \u0441 \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0438 \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0445\u043e\u0434\u0438\u0442\u044c \u0434\u043e \u0438\u0445 \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043e\u0441\u043d\u043e\u0432\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 8.0.0<\/p>\n<p><a class=\"anchor\" name=\"mt6\" id=\"mt6\"><\/a><\/p>\n<h3>\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 DI-\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0432 MassTransit<\/h3>\n<p>\u041a\u043b\u044e\u0447\u0435\u0432\u0443\u044e \u0440\u043e\u043b\u044c \u0432 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0438\u0433\u0440\u0430\u0435\u0442 <strong>ServiceCollectionBusConfigurator<\/strong>. \u041e\u0442 \u043d\u0435\u0433\u043e \u0441\u0442\u0440\u043e\u0438\u0442\u0441\u044f \u0432\u0441\u044f \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0430\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f, \u0432\u043a\u043b\u044e\u0447\u0430\u044f <strong>RegistrationConfigurator<\/strong> \u0438 <strong>DependencyInjectionContainerRegistrar<\/strong>. \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f extension-\u043c\u0435\u0442\u043e\u0434\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u044e\u0442 \u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u0443\u044e\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438.<\/p>\n<p>\u042d\u0442\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u044e\u0442 \u043e\u0441\u043d\u043e\u0432\u0443 DI-\u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0432 MassTransit, \u0438 \u0438\u043c\u0435\u043d\u043d\u043e \u043d\u0430 \u043d\u0438\u0445 \u0441\u0442\u043e\u0438\u0442 \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435.<\/p>\n<ul>\n<li>\n<p><strong>DependencyInjectionContainerRegistrar<\/strong> \u041d\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 DI \u043f\u043e \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0443 &#8212; \u043e\u043d \u043b\u0438\u0448\u044c \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442 \u0444\u0430\u0431\u0440\u0438\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 RequestClient \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044e\u0442 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 ConsumeContext \u0438 \u043f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u0440\u0438\u0432\u044f\u0437\u044b\u0432\u0430\u044e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u043a \u043d\u0435\u043c\u0443. RequestClient \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 consume context, \u0447\u0442\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0443 correlationId, \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432 \u0438 tracing \u043c\u0435\u0436\u0434\u0443 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"cs\">public class DependencyInjectionContainerRegistrar : IContainerRegistrar    {         protected readonly IServiceCollection Collection;        public DependencyInjectionContainerRegistrar(IServiceCollection collection)        {            Collection = collection;        }          public void RegisterRequestClient&lt;T&gt;(RequestTimeout timeout)            where T : class        {            Collection.AddScoped(provider =&gt;            {                var clientFactory = GetClientFactory(provider);                var consumeContext = provider.GetRequiredService&lt;ScopedConsumeContextProvider&gt;().GetContext();                if (consumeContext != null)                    return clientFactory.CreateRequestClient&lt;T&gt;(consumeContext, timeout);                return new ClientFactory(                        new ScopedClientFactoryContext&lt;IServiceProvider&gt;(clientFactory, provider))                    .CreateRequestClient&lt;T&gt;(timeout);            });        }        public void RegisterRequestClient&lt;T&gt;(Uri destinationAddress, RequestTimeout timeout)            where T : class        {            Collection.AddScoped(provider =&gt;            {                var clientFactory = GetClientFactory(provider);                var consumeContext = provider.GetRequiredService&lt;ScopedConsumeContextProvider&gt;().GetContext();                if (consumeContext != null)                    return clientFactory.CreateRequestClient&lt;T&gt;(consumeContext, destinationAddress, timeout);                return new ClientFactory(                        new ScopedClientFactoryContext&lt;IServiceProvider&gt;(clientFactory, provider))                    .CreateRequestClient&lt;T&gt;(destinationAddress, timeout);            });        }...}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<ul>\n<li>\n<p><strong>RegistrationConfigurator \u043a\u0430\u043a \u0444\u0430\u0441\u0430\u0434 DI-\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438<\/strong><\/p>\n<\/li>\n<\/ul>\n<p>RegistrationConfigurator &#8212; \u044d\u0442\u043e \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0432 MassTransit. \u0427\u0435\u0440\u0435\u0437 \u043d\u0435\u0433\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f consumers, sagas, saga state machines, activities, endpoints \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0441\u0438\u0441\u0442\u0435\u043c\u044b, \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u044f \u0435\u0434\u0438\u043d\u044b\u0439 \u0434\u0435\u043a\u043b\u0430\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0441\u043b\u043e\u0439 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u043f\u043e\u0432\u0435\u0440\u0445 Microsoft.Extensions.DependencyInjection.<\/p>\n<pre><code class=\"cs\">public class RegistrationConfigurator :        IRegistrationConfigurator    {        readonly IServiceCollection _collection;        bool _configured;        ISagaRepositoryRegistrationProvider _sagaRepositoryRegistrationProvider;        protected RegistrationConfigurator(IServiceCollection collection, IContainerRegistrar registrar)        {            _collection = collection ?? throw new ArgumentNullException(nameof(collection));            Registrar = registrar ?? new DependencyInjectionContainerRegistrar(collection);            _sagaRepositoryRegistrationProvider = new SagaRepositoryRegistrationProvider();        }        public IContainerRegistrar Registrar { get; }        protected Func&lt;IServiceProvider, IBus, IClientFactory&gt; ClientFactoryProvider { get; } = BusClientFactoryProvider;           public IConsumerRegistrationConfigurator&lt;T&gt; AddConsumer&lt;T&gt;(Action&lt;IConsumerConfigurator&lt;T&gt;&gt; configure)            where T : class, IConsumer        {            return AddConsumer(null, configure);        }        public IConsumerRegistrationConfigurator&lt;T&gt; AddConsumer&lt;T&gt;(Type consumerDefinitionType, Action&lt;IConsumerConfigurator&lt;T&gt;&gt; configure = null)            where T : class, IConsumer        {            var registration = _collection.RegisterConsumer&lt;T&gt;(Registrar, consumerDefinitionType);            registration.AddConfigureAction(configure);            return new ConsumerRegistrationConfigurator&lt;T&gt;(this);        }        public ISagaRegistrationConfigurator&lt;T&gt; AddSaga&lt;T&gt;(Action&lt;ISagaConfigurator&lt;T&gt;&gt; configure)            where T : class, ISaga        {            return AddSaga(null, configure);        }...}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<ul>\n<li>\n<p><strong>ServiceCollectionBusConfigurator &#8212; Composition Root Class MassTransit (Bus + DI \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f)<\/strong> \u042f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0446\u0435\u043d\u0442\u0440\u0430\u043b\u044c\u043d\u044b\u043c \u043a\u043b\u0430\u0441\u0441\u043e\u043c, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0438\u043c \u0437\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044e Bus \u0432 MassTransit. \u041e\u043d \u0441\u0442\u0440\u043e\u0438\u0442 \u0432\u0435\u0441\u044c runtime-\u0441\u043b\u043e\u0439.<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"cs\">    public class ServiceCollectionBusConfigurator :        RegistrationConfigurator,        IBusRegistrationConfigurator    {        public ServiceCollectionBusConfigurator(IServiceCollection collection)            : this(collection, new DependencyInjectionContainerRegistrar(collection))        {            IBusRegistrationContext CreateRegistrationContext(IServiceProvider provider)            {                return new BusRegistrationContext(provider, Registrar);            }            collection.AddSingleton(provider =&gt; ClientFactoryProvider(provider, provider.GetRequiredService&lt;IBus&gt;()));            collection.AddSingleton(provider =&gt; Bind&lt;IBus&gt;.Create(CreateRegistrationContext(provider)));            collection.AddSingleton(provider =&gt; provider.GetRequiredService&lt;Bind&lt;IBus, IBusRegistrationContext&gt;&gt;().Value);            collection.TryAdd(ServiceDescriptor.Singleton(typeof(IReceiveEndpointDispatcher&lt;&gt;), typeof(ReceiveEndpointDispatcher&lt;&gt;)));            collection.AddSingleton&lt;IReceiveEndpointDispatcherFactory&gt;(provider =&gt;            {                var registrationContext = provider.GetRequiredService&lt;Bind&lt;IBus, IBusRegistrationContext&gt;&gt;().Value;                var busInstance = provider.GetRequiredService&lt;Bind&lt;IBus, IBusInstance&gt;&gt;().Value;                return new ReceiveEndpointDispatcherFactory(registrationContext, busInstance);            });        }         protected ServiceCollectionBusConfigurator(IServiceCollection collection, IContainerRegistrar registrar)            : base(collection, registrar)        {            AddMassTransitComponents(collection);        }        public virtual void AddBus(Func&lt;IBusRegistrationContext, IBusControl&gt; busFactory)        {            SetBusFactory(new RegistrationBusFactory(busFactory));        }        public virtual void SetBusFactory&lt;T&gt;(T busFactory)            where T : IRegistrationBusFactory        {            if (busFactory == null)                throw new ArgumentNullException(nameof(busFactory));            ThrowIfAlreadyConfigured(nameof(SetBusFactory));            this.AddSingleton(provider =&gt; Bind&lt;IBus&gt;.Create(CreateBus(busFactory, provider)));            this.AddSingleton(provider =&gt; provider.GetRequiredService&lt;Bind&lt;IBus, IBusInstance&gt;&gt;().Value);            this.AddSingleton&lt;IReceiveEndpointConnector&gt;(provider =&gt; provider.GetRequiredService&lt;Bind&lt;IBus, IBusInstance&gt;&gt;().Value);            this.AddSingleton(provider =&gt; provider.GetRequiredService&lt;Bind&lt;IBus, IBusInstance&gt;&gt;().Value.BusControl);            this.AddSingleton(provider =&gt; provider.GetRequiredService&lt;Bind&lt;IBus, IBusInstance&gt;&gt;().Value.Bus);            Registrar.RegisterScopedClientFactory();        }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><a class=\"anchor\" name=\"mt7\" id=\"mt7\"><\/a><\/p>\n<h3>\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f MassTransit: \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f vs \u0440\u0443\u0447\u043d\u0430\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f<\/h3>\n<p>\u0420\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c \u0432\u0441\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0432 MassTransit \u0433\u043b\u0443\u0431\u043e\u043a\u043e \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u0441\u043c\u044b\u0441\u043b\u0430 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u044d\u0442\u043e\u0433\u043e \u0440\u0430\u0437\u0431\u043e\u0440\u0430, \u0442\u0430\u043a \u043a\u0430\u043a \u043e\u043d\u0430 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0443\u0440\u043e\u0432\u043d\u0435\u0439 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u0438 \u0438 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0445 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u043e\u0432, \u0430 \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u0433\u0440\u0443\u0436\u0435\u043d\u0438\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0431\u044b \u0437\u0430\u0442\u044f\u043d\u0443\u043b\u043e \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b.<\/p>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, BusRegistrationContext \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u0432 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438 ConfigureEndpoints, \u0433\u0434\u0435 MassTransit \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0442\u043e\u043f\u043e\u043b\u043e\u0433\u0438\u044e: \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u043e\u0447\u0435\u0440\u0435\u0434\u0438, \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u0443\u0435\u0442 consumers \u0438 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442 \u0438\u0445 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a endpoint\u2019\u0430\u043c.<\/p>\n<p>\u0412 \u0442\u043e \u0436\u0435 \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 ReceiveEndpoint \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0440\u0443\u0447\u043d\u043e\u0439 &#8212; \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u0430\u043c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0438 \u044f\u0432\u043d\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442 consumers. \u0412 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 ConfigureEndpoints \u043d\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f, \u0442\u0430\u043a \u043a\u0430\u043a endpoint \u0443\u0436\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e.<\/p>\n<p>\u0418\u0437-\u0437\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u044f \u0434\u0432\u0443\u0445 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u0445 \u043c\u043e\u0434\u0435\u043b\u0435\u0439 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 (\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0438 \u0440\u0443\u0447\u043d\u043e\u0439), \u0430 \u0442\u0430\u043a\u0436\u0435 \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0445 \u043f\u0440\u0430\u0432\u0438\u043b \u0438 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439, \u0443\u0433\u043b\u0443\u0431\u043b\u044f\u0442\u044c\u0441\u044f \u0432\u043e \u0432\u0441\u0435 \u0434\u0435\u0442\u0430\u043b\u0438 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430 \u043d\u0435\u0446\u0435\u043b\u0435\u0441\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u0435\u0440\u0435\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0438 \u043d\u0435 \u0437\u0430\u0442\u044f\u0433\u0438\u0432\u0430\u0442\u044c \u0440\u0430\u0437\u0431\u043e\u0440.<\/p>\n<p><a class=\"anchor\" name=\"mt8\" id=\"mt8\"><\/a><\/p>\n<h3>Configuration \u0438 Configurators<\/h3>\n<p>\u0412 MassTransit \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0440\u0430\u0437\u0434\u0435\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043d\u0430 \u0434\u0432\u0430 \u0443\u0440\u043e\u0432\u043d\u044f: Configurator \u0438 Configuration.<\/p>\n<p>Configurator \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0441\u044f \u043a \u0443\u0440\u043e\u0432\u043d\u044e \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f pipeline \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0438 \u043e\u0441\u043d\u043e\u0432\u0430\u043d \u043d\u0430 \u043c\u043e\u0434\u0435\u043b\u0438 GreenPipes. \u041e\u043d \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0446\u0435\u043f\u043e\u0447\u043a\u0438 middleware, \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432 \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u0440\u044f\u0434\u043a\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043b\u043e\u0433\u0438\u043a\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u041d\u0430 \u044d\u0442\u043e\u043c \u0443\u0440\u043e\u0432\u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c \u0432 \u0432\u0438\u0434\u0435 IPipe, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439.<\/p>\n<p>Configuration \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0441\u044f \u043a \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043d\u043e\u043c\u0443 \u0443\u0440\u043e\u0432\u043d\u044e \u0438 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u044b. \u041e\u043d \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 receive endpoint, \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u0435\u0439, exchange, topology \u0438 \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u0442 \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442 \u0441 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u043e\u0439 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u041d\u0430 \u044d\u0442\u043e\u043c \u0443\u0440\u043e\u0432\u043d\u0435 \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0441\u0430\u043c\u0430 \u0442\u043e\u0447\u043a\u0430 \u0432\u0445\u043e\u0434\u0430 \u0434\u043b\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0438 \u0435\u0451 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0441 \u0431\u0440\u043e\u043a\u0435\u0440\u043e\u043c.<\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, Configuration \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0442\u043e, \u0447\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 (endpoint \u0438 \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442), \u0430 Configurator &#8212; \u0437\u0430 \u0442\u043e, \u043a\u0430\u043a \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0432\u043d\u0443\u0442\u0440\u0438 \u044d\u0442\u043e\u0433\u043e endpoint.<\/p>\n<p>Configurators \u0438 configuration-\u043e\u0431\u044a\u0435\u043a\u0442\u044b &#8212; \u044d\u0442\u043e build-time \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f execution pipeline \u0438 state machine. \u041e\u043d\u0438, \u043a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u043d\u0435 \u0443\u0447\u0430\u0441\u0442\u0432\u0443\u044e\u0442 \u0432 runtime execution, \u043d\u043e \u043c\u043e\u0433\u0443\u0442 \u043e\u0441\u0442\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u043f\u0430\u043c\u044f\u0442\u0438, \u0435\u0441\u043b\u0438 \u0443\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 GC roots (DI container, \u0437\u0430\u043c\u044b\u043a\u0430\u043d\u0438\u044f \u0438\u043b\u0438 lifecycle host\u2019a). <\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/XDFRl2x.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/XDFRl2x.png 780w,&#10;       https:\/\/i.imgur.com\/XDFRl2x.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<pre><code class=\"cs\"> public class RabbitMqHostConfiguration :        BaseHostConfiguration&lt;IRabbitMqReceiveEndpointConfiguration, IRabbitMqReceiveEndpointConfigurator&gt;,        IRabbitMqHostConfiguration    {        readonly IRabbitMqBusConfiguration _busConfiguration;        readonly Recycle&lt;IConnectionContextSupervisor&gt; _connectionContext;        readonly IRabbitMqBusTopology _topology;        RabbitMqHostSettings _hostSettings;        public RabbitMqHostConfiguration(IRabbitMqBusConfiguration busConfiguration, IRabbitMqTopologyConfiguration topologyConfiguration)            : base(busConfiguration)        {            _busConfiguration = busConfiguration;            _hostSettings = new ConfigurationHostSettings            {                Host = \"localhost\",                VirtualHost = \"\/\",                Port = 5672,                Username = \"guest\",                Password = \"guest\"            };            var messageNameFormatter = new RabbitMqMessageNameFormatter();            _topology = new RabbitMqBusTopology(this, messageNameFormatter, _hostSettings.HostAddress, topologyConfiguration);            ReceiveTransportRetryPolicy = Retry.CreatePolicy(x =&gt;            {                x.Handle&lt;ConnectionException&gt;();                x.Handle&lt;MessageNotConfirmedException&gt;(exception =&gt;                    exception.Message.Contains(\"CONNECTION_FORCED\")                    || exception.Message.Contains(\"End of stream\")                    || exception.Message.Contains(\"Unexpected Exception\"));                x.Ignore&lt;AuthenticationFailureException&gt;();                x.Exponential(1000, TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(3));            });            _connectionContext = new Recycle&lt;IConnectionContextSupervisor&gt;(() =&gt; new ConnectionContextSupervisor(this, topologyConfiguration));        }        public IConnectionContextSupervisor ConnectionContextSupervisor =&gt; _connectionContext.Supervisor;        public override Uri HostAddress =&gt; _hostSettings.HostAddress;        public bool PublisherConfirmation =&gt; _hostSettings.PublisherConfirmation;        public BatchSettings BatchSettings =&gt; _hostSettings.BatchSettings;        IRabbitMqBusTopology IRabbitMqHostConfiguration.Topology =&gt; _topology;...}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><a class=\"anchor\" name=\"mt9\" id=\"mt9\"><\/a><\/p>\n<h3>Runtime-\u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 MassTransit<\/h3>\n<p>\u041f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f MassTransit \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u0434\u043e\u043b\u0433\u043e\u0436\u0438\u0432\u0443\u0449\u0443\u044e \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432\u0435\u0441\u044c lifetime \u0441\u0435\u0440\u0432\u0438\u0441\u0430. \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441 RabbitMQ (IConnection) \u0438 \u043a\u0430\u043d\u0430\u043b (IModel) \u0434\u043b\u044f \u043a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0446\u0438\u0438 \u0441 \u0431\u0440\u043e\u043a\u0435\u0440\u043e\u043c.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u044b consumer\u2019\u044b, MassTransit \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u043e\u0434\u0438\u043d \u0438\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e receive endpoints:<\/p>\n<ol>\n<li>\n<p>\u0421\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439 \u0434\u043b\u044f \u0437\u0430\u0434\u0430\u0447 \u0448\u0438\u043d\u044b  (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u201cDESKTOPDTE2RH7_TestingOnWebAPIWithDI_bus_ib3oyydsm7ymbtaibdxj7iiqyb\u201d) &#8212; \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043e\u0439 MassTransit<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u201csomething\u201d) &#8212; \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0431\u0438\u0437\u043d\u0435\u0441-\u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0447\u0435\u0440\u0435\u0437 \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0439 Consumer<\/p>\n<\/li>\n<\/ol>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/hQQLd0C.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/hQQLd0C.png 780w,&#10;       https:\/\/i.imgur.com\/hQQLd0C.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p>\u0412 \u0440\u0430\u043c\u043a\u0430\u0445 transport pipeline \u043a\u0430\u0436\u0434\u043e\u0433\u043e endpoint \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f RabbitMqConsumerFilter, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0447\u0430\u0441\u0442\u044c\u044e \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u043d\u043e\u0433\u043e \u0443\u0440\u043e\u0432\u043d\u044f. \u041e\u043d \u0441\u043e\u0437\u0434\u0430\u0451\u0442 RabbitMqBasicConsumer \u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u0442 \u0435\u0433\u043e \u0447\u0435\u0440\u0435\u0437 BasicConsume \u0432 RabbitMQ.Client, \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u044f\u0441\u044c \u043d\u0430 \u043e\u0447\u0435\u0440\u0435\u0434\u044c. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0441\u0432\u044f\u0437\u044c \u043c\u0435\u0436\u0434\u0443 RabbitMQ \u0438 MassTransit.<\/p>\n<pre><code class=\"cs\">public class RabbitMqConsumerFilter :        IFilter&lt;ModelContext&gt;    {        readonly RabbitMqReceiveEndpointContext _context;        string _consumerTag;        public RabbitMqConsumerFilter(RabbitMqReceiveEndpointContext context)        {            _context = context;            _consumerTag = \"\";        }        void IProbeSite.Probe(ProbeContext context)        {        }        async Task IFilter&lt;ModelContext&gt;.Send(ModelContext context, IPipe&lt;ModelContext&gt; next)        {            var receiveSettings = context.GetPayload&lt;ReceiveSettings&gt;();           ** var consumer = new RabbitMqBasicConsumer(context, _context);**            _consumerTag = await context.BasicConsume(                receiveSettings.QueueName,                receiveSettings.NoAck,                _context.ExclusiveConsumer,                receiveSettings.ConsumeArguments,                consumer,                _consumerTag            ).ConfigureAwait(false);            await consumer.Ready.ConfigureAwait(false);            _context.AddConsumeAgent(consumer);            await _context.TransportObservers.NotifyReady(_context.InputAddress).ConfigureAwait(false);            try            {                await consumer.Completed.ConfigureAwait(false);            }            finally            {                RabbitMqDeliveryMetrics metrics = consumer;                await _context.TransportObservers.NotifyCompleted(_context.InputAddress, metrics).ConfigureAwait(false);                LogContext.Debug?.Log(                    \"Consumer completed {ConsumerTag}: {DeliveryCount} received, {ConcurrentDeliveryCount} concurrent\",                    metrics.ConsumerTag,                    metrics.DeliveryCount,                    metrics.ConcurrentDeliveryCount                );            }            await next.Send(context).ConfigureAwait(false);        }    }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<pre><code class=\"cs\"> public class RabbitMqModelContext :        ScopePipeContext,        ModelContext,        IAsyncDisposable    {        readonly CancellationToken _cancellationToken;        readonly PendingConfirmationCollection _confirmations;        readonly ConnectionContext _connectionContext;        readonly ChannelExecutor _executor;        readonly IModel _model;        readonly IPublisher _publisher;...Task&lt;string&gt; ModelContext.BasicConsume(string queue, bool noAck, bool exclusive, IDictionary&lt;string, object&gt; arguments, IBasicConsumer consumer,            string consumerTag)        {            return _executor.Run(() =&gt; _model.BasicConsume(consumer, queue, noAck, consumerTag, false, exclusive, arguments), CancellationToken);        }...}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041a\u0430\u0436\u0434\u044b\u0439 endpoint \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u0442 \u043e\u0447\u0435\u0440\u0435\u0434\u044c RabbitMQ, \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u043d\u044b\u0439 \u0441\u043b\u043e\u0439 \u0438 pipeline \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438.<\/p>\n<p>\u0420\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043f\u043e pipeline\u2019\u0430\u043c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0443\u0436\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 MassTransit <strong>transport layer \u0447\u0435\u0440\u0435\u0437 ReceivePipeDispatcher \u0438 ReceivePipe<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0442 middleware pipeline \u0438 consumer pipeline \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e receive endpoint\u2019\u0430.<\/p>\n<p><a class=\"anchor\" name=\"mt10\" id=\"mt10\"><\/a><\/p>\n<h3>\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438 \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f<\/h3>\n<p>\u0421\u0442\u043e\u0438\u0442 \u043f\u043e\u043c\u043d\u0438\u0442\u044c, \u0447\u0442\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 MassTransit \u043d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0435\u0434\u0438\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u043e\u0439, \u043d\u043e \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0434\u0435\u043b\u0438\u0442\u0441\u044f \u043d\u0430 \u0434\u0432\u0430 \u0443\u0440\u043e\u0432\u043d\u044f: <strong>Transport Layer<\/strong> \u0438 <strong>Consumer Layer<\/strong><\/p>\n<p>Transport Layer \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 ReceiveContext, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0441\u044b\u0440\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0438 \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u043d\u044b\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, routing key). \u041d\u0430 \u044d\u0442\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u0431\u0438\u0437\u043d\u0435\u0441-\u043c\u043e\u0434\u0435\u043b\u044c \u0435\u0449\u0451 \u043d\u0435 \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0430.<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u0447\u0435\u0440\u0435\u0437 ReceivePipeLine. \u0412 DeserializerFilter \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043a\u043b\u044e\u0447\u0435\u0432\u043e\u0439 \u043c\u043e\u043c\u0435\u043d\u0442: \u0438\u0437 ReceiveContext \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442\u0441\u044f ConsumeContext, \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u0442 \u0432 Consumer Layer.<\/p>\n<pre><code class=\"cs\">public class DeserializeFilter :        IFilter&lt;ReceiveContext&gt;    {        readonly IPipe&lt;ConsumeContext&gt; _output;        readonly ISerialization _serializers;        public DeserializeFilter(ISerialization serializers, IPipe&lt;ConsumeContext&gt; output)        {            _serializers = serializers;            _output = output;        }        public void Probe(ProbeContext context)        {            var scope = context.CreateFilterScope(\"deserialize\");            _serializers.Probe(scope);            _output.Probe(scope);        }        [DebuggerNonUserCode]        public async Task Send(ReceiveContext context, IPipe&lt;ReceiveContext&gt; next)        {            if (!context.TryGetPayload(out ConsumeContext consumeContext))                consumeContext = _serializers.GetMessageDeserializer(context.ContentType).Deserialize(context);            Activity.Current?.AddConsumeContextTags(consumeContext);            await _output.Send(consumeContext).ConfigureAwait(false);            await next.Send(context).ConfigureAwait(false);            await consumeContext.ConsumeCompleted.ConfigureAwait(false);        }    }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0421 \u044d\u0442\u043e\u0433\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u0443\u0436\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0430 &#8212; consumers, sagas \u0438 ConsumePipeLine.<\/p>\n<p><a class=\"anchor\" name=\"mt11\" id=\"mt11\"><\/a><\/p>\n<h3>Pipeline \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 MassTransit<\/h3>\n<p>\u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u043e\u0441\u0442\u0443\u043f\u0430\u0435\u0442 \u0438\u0437 RabbitMQ \u0447\u0435\u0440\u0435\u0437 RabbitMqBasicConsumer \u0432 ReceivePipeDispatcher, \u0433\u0434\u0435 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f ReceiveContext.<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u043e\u043d\u043e \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 transport pipeline (ReceivePipe) \u0441 \u0431\u0430\u0437\u043e\u0432\u044b\u043c\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430\u043c\u0438 \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u043e\u0439 \u043e\u0448\u0438\u0431\u043e\u043a: Rescue \u0438 DeadLetter \u0430\u043a\u0442\u0438\u0432\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438 \u0441\u0431\u043e\u044f\u0445 \u0438\u043b\u0438 \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438.<\/p>\n<p>\u0417\u0430\u0442\u0435\u043c DeserializeFilter \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432 \u0442\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 ConsumeContext.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/WLzN5an.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/WLzN5an.png 780w,&#10;       https:\/\/i.imgur.com\/WLzN5an.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<h3>ReceivePipeDispatcher &#8212; \u043e\u0440\u043a\u0435\u0441\u0442\u0440\u0430\u0442\u043e\u0440 \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439<\/h3>\n<p>\u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u0448\u043b\u043e \u0438\u0437 RabbitMQ. \u041d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0442\u0430\u043a \u0435\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0435\u043b\u044c\u0437\u044f &#8212; \u043d\u0443\u0436\u043d\u0430 \u0441\u0442\u0440\u043e\u0433\u0430\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439. \u0412\u043e\u0442 \u0437\u0434\u0435\u0441\u044c \u0438 \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f ReceivePipeDispatcher.<\/p>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u043d \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 ReceiveContext &#8212; \u044d\u0442\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432 \u0435\u0433\u043e \u201c\u0441\u044b\u0440\u043e\u043c\u201d \u0432\u0438\u0434\u0435.<\/p>\n<p>\u0417\u0430\u0442\u0435\u043c \u043e\u043d \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u044f\u0435\u0442 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u0435\u0439 \u043e \u0441\u043e\u0431\u044b\u0442\u0438\u0438 PreReceive &#8212; \u044d\u0442\u043e \u0442\u043e\u0447\u043a\u0430, \u0433\u0434\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0434\u0446\u0435\u043f\u0438\u0442\u044c \u043b\u044e\u0431\u0443\u044e \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433\u0430 \u0438\u043b\u0438 \u0430\u0443\u0434\u0438\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043b \u041a\u0440\u0438\u0441\u0441 \u041f\u0430\u0442\u0442\u0435\u0440\u0441\u043e\u043d.<\/p>\n<p>\u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432 ReceivePipe &#8212; \u0434\u0430\u043b\u044c\u0448\u0435 \u0432 \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a ReceivePipe \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442 \u0440\u0430\u0431\u043e\u0442\u0443, \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440 \u0436\u0434\u0451\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u044f ReceiveCompleted, \u0447\u0442\u043e\u0431\u044b \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u0432\u0441\u044f \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0430\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043b\u0430\u0441\u044c.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0441\u0451 \u043f\u0440\u043e\u0448\u043b\u043e \u0443\u0441\u043f\u0435\u0448\u043d\u043e, \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440 \u044f\u0432\u043d\u043e \u0433\u043e\u0432\u043e\u0440\u0438\u0442 \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u0443: \u201c\u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043e, \u043c\u043e\u0436\u043d\u043e \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0438\u0437 \u043e\u0447\u0435\u0440\u0435\u0434\u0438\u201d.<\/p>\n<p>\u0418 \u043d\u0430\u043a\u043e\u043d\u0435\u0446, \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u044f\u0435\u0442 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u0435\u0439 \u043e \u0441\u043e\u0431\u044b\u0442\u0438\u0438 PostReceive &#8212; \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u043e.<\/p>\n<pre><code class=\"cs\">public class ReceivePipeDispatcher :        IReceivePipeDispatcher    {        readonly string _activityName;        readonly IHostConfiguration _hostConfiguration;        readonly ReceiveObservable _observers;        readonly IReceivePipe _receivePipe;        int _activeDispatchCount;        long _dispatchCount;        int _maxConcurrentDispatchCount;...public async Task Dispatch(ReceiveContext context, ReceiveLockContext receiveLock = default)        {            LogContext.SetCurrentIfNull(_hostConfiguration.ReceiveLogContext);            var active = StartDispatch();            StartedActivity? activity = LogContext.IfEnabled(_activityName)?.StartReceiveActivity(context);            try            {                if (_observers.Count &gt; 0)                    await _observers.PreReceive(context).ConfigureAwait(false);                if (receiveLock != null)                    await receiveLock.ValidateLockStatus().ConfigureAwait(false);                await _receivePipe.Send(context).ConfigureAwait(false);                await context.ReceiveCompleted.ConfigureAwait(false);                if (receiveLock != null)                    await receiveLock.Complete().ConfigureAwait(false);                if (_observers.Count &gt; 0)                    await _observers.PostReceive(context).ConfigureAwait(false);            }            catch (Exception ex)            {                if (_observers.Count &gt; 0)                    await _observers.ReceiveFault(context, ex).ConfigureAwait(false);                if (receiveLock != null)                {                    try                    {                        await receiveLock.Faulted(ex).ConfigureAwait(false);                    }                    catch (Exception releaseLockException)                    {                        throw new AggregateException(\"ReceiveLock.Faulted threw an exception\", releaseLockException, ex);                    }                }                throw;            }            finally            {                activity?.Stop();                await active.Complete().ConfigureAwait(false);            }        }...}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><a class=\"anchor\" name=\"mt12\" id=\"mt12\"><\/a><\/p>\n<h3>ChannelExecutor<\/h3>\n<p>\u041f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u043d\u044b\u043c \u0443\u0440\u043e\u0432\u043d\u0435\u043c MassTransit \u0438 RabbitMQ \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e ChannelExecutor \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d \u043d\u0435 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e.<\/p>\n<p>\u0412 \u043e\u0441\u043d\u043e\u0432\u0435 \u043c\u043e\u0434\u0435\u043b\u0438 \u043b\u0435\u0436\u0438\u0442 \u043f\u043e\u043d\u044f\u0442\u0438\u0435 shared protocol state. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 RabbitMQ.Client \u0442\u0430\u043a\u0438\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f TCP-\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435, \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u044e\u0442\u0441\u044f \u043a\u0430\u043d\u0430\u043b\u044b (IModel \/ IChannel).<\/p>\n<p>\u0412\u0441\u0435 \u043a\u0430\u043d\u0430\u043b\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u043e\u0434\u0438\u043d \u043e\u0431\u0449\u0438\u0439 \u043f\u043e\u0442\u043e\u043a \u0437\u0430\u043f\u0438\u0441\u0438 (frame writer), \u043f\u043e\u044d\u0442\u043e\u043c\u0443 IChannel \u043d\u0435\u043b\u044c\u0437\u044f \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u0437 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e &#8212; \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u043d\u0430\u0440\u0443\u0448\u0435\u043d\u0438\u044e AMQP framing \u0438 \u043d\u0435\u043a\u043e\u043d\u0441\u0438\u0441\u0442\u0435\u043d\u0442\u043d\u043e\u0441\u0442\u0438 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u044c\u043d\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f. \u041e\u0442\u0441\u044e\u0434\u0430 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0437\u0430\u043a\u0440\u044b\u0442\u043e, \u043f\u043e\u0442\u0435\u0440\u044f\u043d\u044b \u043d\u0435\u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/QAVujnL.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/QAVujnL.png 780w,&#10;       https:\/\/i.imgur.com\/QAVujnL.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p><a href=\"https:\/\/www.rabbitmq.com\/client-libraries\/dotnet-api-guide#concurrency\" rel=\"noopener noreferrer nofollow\">https:\/\/www.rabbitmq.com\/client-libraries\/dotnet-api-guide#concurrency<\/a><\/p>\n<p><a class=\"anchor\" name=\"mt13\" id=\"mt13\"><\/a><\/p>\n<h3>Pipeline \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 MassTransit<\/h3>\n<p>\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0441 \u0432\u044b\u0437\u043e\u0432\u0430 \u043c\u0435\u0442\u043e\u0434\u0430 Publish &#8212; \u0442\u043e\u0447\u043a\u0438 \u0432\u0445\u043e\u0434\u0430 \u0432 pipeline \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u041e\u043d \u0434\u0435\u043b\u0435\u0433\u0438\u0440\u0443\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0432 PublishInternal, \u0433\u0434\u0435 \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442\u0441\u044f PublishContext \u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u044e\u0442\u0441\u044f middleware.<\/p>\n<p>\u041d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u043b\u043e\u0433\u0438\u043a\u0438 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u0447\u0435\u0440\u0435\u0437 SendEndpointProxy \u0438 CachedSendEndpoint, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043a\u044d\u0448\u0438\u0440\u0443\u044e\u0442 \u0438 \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 endpoint\u2019\u044b \u0434\u043b\u044f \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438. \u0417\u0430\u0442\u0435\u043c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u0442 \u0432 SendEndpoint, \u0433\u0434\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 send pipeline.<\/p>\n<p>\u0422\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u043d\u044b\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d RabbitMqSendTransport &#8212; \u043e\u043d \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u0443\u0435\u0442 MassTransit \u0441 RabbitMQ \u0438 \u043f\u043e\u0434\u0433\u043e\u0442\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043a \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0435. \u041d\u0430 \u044d\u0442\u043e\u043c \u0443\u0440\u043e\u0432\u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f ConnectionContextSupervisor \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u043c \u0446\u0438\u043a\u043b\u043e\u043c \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0439 \u0438 \u043e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0432 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c retry (HostConfigurationRetryExtensions), \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u044f \u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u043e\u0441\u0442\u044c \u043a \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c \u0441\u0431\u043e\u044f\u043c.<\/p>\n<p>\u0414\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 MassTransit \u0442\u043e\u0442 \u0436\u0435 ChannelExecutor \u0447\u0442\u043e\u0431 \u043d\u0435 \u0441\u043b\u043e\u043c\u0430\u0442\u044c AMQP Framing.<\/p>\n<p>\u0427\u0435\u0440\u0435\u0437 PipeContextSupervisor \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442\u0441\u044f ModelContext, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 RabbitMQ \u043a\u0430\u043d\u0430\u043b (IModel). \u041d\u0430 \u044d\u0442\u0430\u043f\u0435 SendPipe \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u043a\u043e\u043d\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442\u0441\u044f: \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u0431\u0430\u0439\u0442\u044b, \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u044e\u0442\u0441\u044f IBasicProperties, \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0438 routing key.<\/p>\n<p>\u0412\u044b\u0437\u043e\u0432 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u0447\u0435\u0440\u0435\u0437 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043e\u0431\u0451\u0440\u0442\u043e\u043a ModelContext (SharedModelContext, ScopeModelContext, RabbitMqModelContext), \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442 \u043e\u0431\u043b\u0430\u0441\u0442\u044c\u044e \u0436\u0438\u0437\u043d\u0438 \u043a\u0430\u043d\u0430\u043b\u0430 \u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c\u0438.<\/p>\n<p>\u0424\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0448\u0430\u0433 &#8212; ImmediatePublisher.Publish, \u0433\u0434\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f BasicPublish \u0447\u0435\u0440\u0435\u0437 ChannelExecutor, \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u043f\u043e\u0442\u043e\u043a\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u0443\u044e \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u043a\u0430\u043d\u0430\u043b\u043e\u043c. \u0417\u0434\u0435\u0441\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432 RabbitMQ exchange. \u041f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c publisher confirms \u0434\u043b\u044f \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0438 \u043e\u0442 \u0431\u0440\u043e\u043a\u0435\u0440\u0430.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/qSkfJNd.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/qSkfJNd.png 780w,&#10;       https:\/\/i.imgur.com\/qSkfJNd.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p><a class=\"anchor\" name=\"mt14\" id=\"mt14\"><\/a><\/p>\n<h3>Sagas<\/h3>\n<p>\u0413\u043b\u0430\u0432\u043d\u044b\u0439  \u043f\u0430\u0442\u0442\u0435\u0440\u043d StateMachine, \u043f\u043e \u0441\u0443\u0442\u0438 \u0433\u043e\u0432\u043e\u0440\u044f \u043b\u044e\u0431\u0430\u044f \u201c\u043c\u0430\u0448\u0438\u043d\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439\u201d &#8212; \u044d\u0442\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u0438 \u043e\u043d\u0438 \u0434\u0435\u0440\u0436\u0430\u0442\u0441\u044f \u043d\u0430 4\u0435\u0445 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u043a\u0430\u043a \u0435\u0434\u0438\u043d\u043e\u0435 \u0446\u0435\u043b\u043e\u0435:<\/p>\n<ol>\n<li>\n<p>States &#8212; \u041e\u0431\u044a\u0435\u043a\u0442\u044b State<\/p>\n<\/li>\n<li>\n<p>Events &#8212; \u0422\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f<\/p>\n<\/li>\n<li>\n<p>Transitions &#8212; \u044f\u0432\u043d\u044b\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u0430(During\/When)<\/p>\n<\/li>\n<li>\n<p>Activities &#8212; \u044f\u0432\u043d\u044b\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f<\/p>\n<\/li>\n<\/ol>\n<p>\u042f\u0440\u043a\u043e\u0435 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441 AsyncStateMachine, \u0433\u0434\u0435 \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c \u043e\u0434\u043d\u0430 \u0438 \u0442\u0430 \u0436\u0435 &#8212; \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u0430\u0432\u0442\u043e\u043c\u0430\u0442.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/cNs1yI1.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/cNs1yI1.png 780w,&#10;       https:\/\/i.imgur.com\/cNs1yI1.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p>\u041d\u0430 \u043c\u0435\u0441\u0442\u0435  States \u0443 \u043d\u0430\u0441 \u0447\u0438\u0441\u043b\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u0442.\u0435 0,1,2\u2026 \u041d\u0430 \u043c\u0435\u0441\u0442\u0435 Events \u0442\u0430\u043c \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435 \u0447\u0435\u0440\u0435\u0437 await \u041d\u0430 \u043c\u0435\u0441\u0442\u0435 Transitions \u0443 \u043d\u0430\u0441 \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u043a\u043e\u0434\u0430 \u0433\u0434\u0435 \u0431\u0443\u0434\u0435\u0442 \u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u041d\u0430 \u043c\u0435\u0441\u0442\u0435 Activities \u0442\u0435\u043b\u043e \u043c\u0435\u0442\u043e\u0434\u0430<\/p>\n<p><a class=\"anchor\" name=\"mt15\" id=\"mt15\"><\/a><\/p>\n<h3>SagaStateMachine \u0438 FSM<\/h3>\n<p>SagaStateMachine \u0438 \u043b\u044e\u0431\u0430\u044f StateMachine \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 FSM \u0442.\u0435 Finite State Machine.<\/p>\n<p>\u0423 \u043b\u044e\u0431\u043e\u0439 state machine \u0432\u0441\u0435\u0433\u0434\u0430 \u0435\u0441\u0442\u044c \u0438 \u0431\u0443\u0434\u0443\u0442 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u043e\u043d\u044f\u0442\u0438\u044f, \u043a\u0430\u043a State, Event\/Input, Transition, Activity\/Action<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/IV02yvA.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/IV02yvA.png 780w,&#10;       https:\/\/i.imgur.com\/IV02yvA.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p><a href=\"https:\/\/en.wikipedia.org\/wiki\/Finite-state_machine\" rel=\"noopener noreferrer nofollow\">https:\/\/en.wikipedia.org\/wiki\/Finite-state_machine<\/a> <\/p>\n<p>\u0418 \u044d\u0442\u043e \u043f\u043e \u0441\u0443\u0442\u0438 \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c, \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0449\u0430\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0440\u043e\u0432\u043d\u043e \u0432 \u043e\u0434\u043d\u043e\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u0438\u0437 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0433\u043e \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0430 \u0432 \u043b\u044e\u0431\u043e\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u0438. \u0421\u0438\u0441\u0442\u0435\u043c\u0430 \u043c\u0435\u043d\u044f\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 (\u043f\u0435\u0440\u0435\u0445\u043e\u0434) \u043f\u043e\u0434 \u0432\u043e\u0437\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435\u043c \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0438\u043b\u0438 \u0432\u0445\u043e\u0434\u043d\u044b\u0445 \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u0432. FSM \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043b\u043e\u0433\u0438\u043a\u043e\u0439 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c, \u0418\u0418 \u0432 \u0438\u0433\u0440\u0430\u0445 \u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u0445\u0435\u043c<\/p>\n<p>\u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0435\u0451 \u043c\u043e\u0436\u043d\u043e \u0432\u0432\u0438\u0434\u0435 \u0413\u0440\u0430\u0444\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u0442.\u0435<\/p>\n<ol>\n<li>\n<p>\u0412\u0435\u0440\u0448\u0438\u043d\u044b &#8212; \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f(Pending\/Completed)<\/p>\n<\/li>\n<li>\n<p>\u0420\u0435\u0431\u0440\u0430 &#8212; \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044b(OrderPaid)<\/p>\n<\/li>\n<\/ol>\n<p>\u0414\u043e\u043f\u0443\u0441\u0442\u0438\u043c Pending \u2013 (OrderPaid) \u2013 Completed<\/p>\n<p>\u041a\u043b\u044e\u0447\u0435\u0432\u0430\u044f \u0438\u0434\u0435\u044f: \u0422\u0435\u043a\u0443\u0449\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 + \u0421\u043e\u0431\u044b\u0442\u0438\u0435 \u2192 \u041f\u0435\u0440\u0435\u0445\u043e\u0434 \u2192 \u041d\u043e\u0432\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 + \u0414\u0435\u0439\u0441\u0442\u0432\u0438\u0435<\/p>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0438\u043b\u0438 \u0432\u0445\u043e\u0434\u043d\u043e\u0439 \u0441\u0438\u0433\u043d\u0430\u043b, \u043e\u043d\u0430 \u043c\u043e\u0436\u0435\u0442:<\/p>\n<ul>\n<li>\n<p>\u043e\u0441\u0442\u0430\u0442\u044c\u0441\u044f \u0432 \u0442\u0435\u043a\u0443\u0449\u0435\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438<\/p>\n<\/li>\n<li>\n<p>\u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435<\/p>\n<\/li>\n<li>\n<p>\u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u0432 \u0434\u0440\u0443\u0433\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435<\/p>\n<\/li>\n<\/ul>\n<p>\u0422\u0430\u043a \u0436\u0435 AsyncStateMachine \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043f\u043e \u0441\u0443\u0442\u0438 DFA \u0442.\u0435 Deterministic Finite Automaton. \u0412 \u043a\u0430\u0436\u0434\u043e\u0439 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438 \u043f\u0443\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/lDiZmbI.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/lDiZmbI.png 780w,&#10;       https:\/\/i.imgur.com\/lDiZmbI.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p><a href=\"https:\/\/en.wikipedia.org\/wiki\/Finite-state_machine\" rel=\"noopener noreferrer nofollow\">https:\/\/en.wikipedia.org\/wiki\/Finite-state_machine<\/a> <\/p>\n<p><a class=\"anchor\" name=\"mt16\" id=\"mt16\"><\/a><\/p>\n<h3>Sagas \u0432\u043d\u0443\u0442\u0440\u0438 MassTransit<\/h3>\n<p>\u041a\u0430\u0441\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430 \u0421\u0430\u0433\u0430 \u0432 \u044d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u0435 MassTransit \u0432\u0430\u0436\u043d\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u043e\u0435 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 \u0434\u0432\u0430 \u0443\u0440\u043e\u0432\u043d\u044f. \u0415\u0441\u043b\u0438 \u043c\u044b \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u0438\u043b\u0438 \u043f\u0440\u043e\u0435\u043a\u0442, \u0442\u043e \u0443\u0432\u0438\u0434\u0438\u043c \u043f\u0430\u043f\u043a\u0438 Sagas \u0438 SagaStateMachine.<\/p>\n<p>\u0421\u043c\u044b\u0441\u043b \u044d\u0442\u043e\u0433\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0444\u0443\u043d\u0434\u0430\u043c\u0435\u043d\u0442\u0430\u043b\u0435\u043d: \u041f\u0435\u0440\u0432\u044b\u0439 \u0441\u043b\u043e\u0439: Sagas &#8212; \u044d\u0442\u043e \u00ab\u043e\u0431\u0432\u044f\u0437\u043a\u0430\u00bb. \u041e\u043d \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430 \u043a \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c\u0443 \u0434\u0432\u0438\u0436\u043a\u0443 MassTransit (GreenPipes), \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f\u043c\u0438 \u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0438\u0437 \u043e\u0447\u0435\u0440\u0435\u0434\u0438. \u0412\u0442\u043e\u0440\u043e\u0439 \u0441\u043b\u043e\u0439: SagaStateMachine &#8212; \u044d\u0442\u043e \u0443\u0436\u0435 \u0441\u0430\u043c\u0430 \u043b\u043e\u0433\u0438\u043a\u0430 \u043e\u0440\u043a\u0435\u0441\u0442\u0440\u0430\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 Pipeline \u0432\u043d\u0443\u0442\u0440\u0438 \u043e\u0431\u043e\u043b\u043e\u0447\u043a\u0438 \u0441\u0430\u0433\u0438.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/RoIOqSI.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/RoIOqSI.png 780w,&#10;       https:\/\/i.imgur.com\/RoIOqSI.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p><a class=\"anchor\" name=\"mt17\" id=\"mt17\"><\/a><\/p>\n<h3>SagaStateMachine<\/h3>\n<p>\u0415\u0441\u043b\u0438 \u0443\u0433\u043b\u0443\u0431\u0438\u0442\u044c\u0441\u044f \u0432 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e StateMachine, \u0442\u043e \u043c\u044b \u0443\u0432\u0438\u0434\u0438\u043c \u0437\u043d\u0430\u043a\u043e\u043c\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b GreenPipes, \u043d\u043e \u0432 \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u043e\u0431\u0451\u0440\u0442\u043a\u0430\u0445:<\/p>\n<ul>\n<li>\n<p>Accessors \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0442 \u0437\u0430 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0434\u0430\u043d\u043d\u044b\u043c \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 \u0441\u0430\u0433\u0438(\u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0441\u0430\u0433\u0438, \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c).<\/p>\n<\/li>\n<li>\n<p>Activities \u043d\u0430\u0448\u0438 \u0431\u0438\u0437\u043d\u0435\u0441-\u0448\u0430\u0433\u0438, \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u0435 \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u043c (Filters) \u0432 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u043c \u0432 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u043c \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440\u0435.<\/p>\n<\/li>\n<li>\n<p>Behaviours \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442 \u043f\u043e\u0440\u044f\u0434\u043a\u043e\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f Activities, \u0440\u0430\u0431\u043e\u0442\u0430\u044f \u043a\u0430\u043a \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b (Pipes). \u0412\u043c\u0435\u0441\u0442\u043e \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u044b\u0445 \u043d\u0430\u043c PipeBuilders, \u0441\u0431\u043e\u0440\u043a\u0443 \u0432\u0441\u0435\u0433\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0437\u0434\u0435\u0441\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 Binders.<\/p>\n<\/li>\n<li>\n<p>Binders &#8212; \u044d\u0442\u043e \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0434\u0435\u043a\u043b\u0430\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0439 DSL (When\/Then\/TransitionTo) \u0432 \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u044b\u0439 pipeline (Behavior).<\/p>\n<\/li>\n<li>\n<p>Correlation \u043f\u0440\u0430\u0432\u0438\u043b\u043e \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0441 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u043e\u043c \u0441\u0430\u0433\u0438, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442, \u043a\u0430\u043a \u043f\u043e \u0434\u0430\u043d\u043d\u044b\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043d\u0430\u0439\u0442\u0438 \u0438\u043b\u0438 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0443\u044e \u0441\u0430\u0433\u0443 \u0432 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412\u043d\u0443\u0442\u0440\u0438 StateMachine \u0432 MassTransit \u043b\u0435\u0436\u0438\u0442 \u0433\u0440\u0430\u0444 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 &#8212; \u0434\u0435\u043a\u043b\u0430\u0440\u0430\u0442\u0438\u0432\u043d\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c, \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0449\u0430\u044f \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u0439 \u0446\u0438\u043a\u043b \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/hGgdfjV.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/hGgdfjV.png 780w,&#10;       https:\/\/i.imgur.com\/hGgdfjV.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p>\u041f\u043e \u0441\u0443\u0442\u0438 \u0433\u043e\u0432\u043e\u0440\u044f \u043d\u0430\u0448\u0430 \u043c\u0430\u0448\u0438\u043d\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u0437\u0434\u0435\u0441\u044c \u0438 \u043e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0444\u0438\u0448\u043a\u0430 MassTransit \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 Sagas \u0432\u043e\u0442 \u0432 \u044d\u0442\u043e\u043c \u0437\u0430\u043c\u0435\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u043c \u0438 \u043f\u0440\u043e\u0441\u0442\u043e\u043c DSL<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/sARPdVT.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/sARPdVT.png 780w,&#10;       https:\/\/i.imgur.com\/sARPdVT.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p><a class=\"anchor\" name=\"mt18\" id=\"mt18\"><\/a><\/p>\n<h3>States \u0432 SagaStateMachine<\/h3>\n<p>\u0415\u0441\u043b\u0438 \u0437\u0430\u0433\u043b\u044f\u043d\u0443\u0442\u044c \u0432\u043d\u0443\u0442\u0440\u044c State, \u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 Property, \u0430 \u044d\u0442\u043e Enter\/Leave\/BeforeEnter\/AfterLeave<\/p>\n<p>\u041f\u0440\u0438\u043d\u0446\u0438\u043f \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439: BeforeEnter \u2192 SetState \u2192 AfterLeave \u2192 Enter<\/p>\n<p>\u041f\u043e \u0441\u0443\u0442\u0438 \u0433\u043e\u0432\u043e\u0440\u044f \u041a\u0440\u0438\u0441\u0441 \u041f\u0430\u0442\u0442\u0435\u0440\u0441\u043e\u043d \u0445\u043e\u0442\u0435\u043b \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0443 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0438, \u043d\u043e \u0438 \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043e\u043d \u0441\u0434\u0435\u043b\u0430\u043b lifecycle \u0445\u0443\u043a\u0438. \u0418 \u043e\u043d\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0434\u043b\u044f Transitions \u0442.\u0435 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u043e\u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f.<\/p>\n<p>\u0412 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0445 \u043a\u0440\u0438\u0442\u0438\u0447\u043d\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c, \u043a\u043e\u0433\u0434\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0435\u0449\u0451 \u0441\u0442\u0430\u0440\u043e\u0435, \u043a\u043e\u0433\u0434\u0430 \u043e\u043d\u043e \u0443\u0436\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u043e \u0438 \u0432 \u043a\u0430\u043a\u043e\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c side-effects(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0443 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f)<\/p>\n<p>\u0427\u0443\u0442\u044c \u043f\u043e\u0437\u0436\u0435 \u043c\u044b \u0443\u0432\u0438\u0434\u0438\u043c \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044b \u044d\u0442\u0438\u0445 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u0432 TransitionActivity.cs \u0444\u0430\u0439\u043b\u0435<\/p>\n<pre><code class=\"cs\">public interface State :        IVisitable,        IComparable&lt;State&gt;    {        string Name { get; }               Event Enter { get; }                Event Leave { get; }               Event&lt;State&gt; BeforeEnter { get; }                Event&lt;State&gt; AfterLeave { get; }    }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><a class=\"anchor\" name=\"mt19\" id=\"mt19\"><\/a><\/p>\n<h3>SagaStateMachine \u0438 Graphs<\/h3>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u043d\u0430\u0447\u043d\u0451\u0442\u0435 \u0438\u0437\u0443\u0447\u0430\u0442\u044c \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 MassTransit, \u043f\u043e\u0447\u0442\u0438 \u043d\u0435\u0438\u0437\u0431\u0435\u0436\u043d\u043e \u0432\u044b \u043f\u0440\u0438\u0434\u0451\u0442\u0435 \u043a \u0442\u0435\u043c\u0435 \u0441\u0430\u0433. \u0418 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043d\u0435\u043e\u0436\u0438\u0434\u0430\u043d\u043d\u043e \u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0442\u044c \u0442\u0430\u043c \u0433\u0440\u0430\u0444\u044b.<\/p>\n<p>\u041d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434 \u044d\u0442\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u0442\u0440\u0430\u043d\u043d\u043e: \u0437\u0430\u0447\u0435\u043c \u043c\u0430\u0448\u0438\u043d\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0443\u0436\u0435\u043d \u0433\u0440\u0430\u0444? \u041d\u043e \u0434\u0435\u043b\u043e \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043e\u043d \u0442\u0430\u043c \u043d\u0435 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e.<\/p>\n<p>\u0410\u0432\u0442\u043e\u0440 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u041a\u0440\u0438\u0441 \u041f\u0430\u0442\u0435\u0440\u0441\u043e\u043d, \u0434\u043e\u0431\u0430\u0432\u0438\u043b \u044d\u0442\u043e \u043e\u0441\u043e\u0437\u043d\u0430\u043d\u043d\u043e. \u0425\u043e\u0442\u044f \u0441\u0430\u043c\u0430 SagaStateMachine \u043e\u0442\u043b\u0438\u0447\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0431\u0435\u0437 \u043a\u0430\u043a\u043e\u0439-\u043b\u0438\u0431\u043e \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438, \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044f\u0445 \u043e\u043d\u0430 \u043c\u043e\u0436\u0435\u0442 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0441\u043b\u043e\u0436\u043d\u043e\u0439: \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439, \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u043e\u0432 \u0440\u0430\u0441\u0442\u0451\u0442, \u0438 \u0443\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u0432\u0441\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u0432 \u0433\u043e\u043b\u043e\u0432\u0435 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0437\u0430\u0442\u0440\u0443\u0434\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e.<\/p>\n<p>\u0412 \u0442\u0430\u043a\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u0433\u0440\u0430\u0444 \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u0435\u0442 \u043a\u0430\u043a \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u201c\u0432\u0442\u043e\u0440\u043e\u0433\u043e \u0432\u0437\u0433\u043b\u044f\u0434\u0430\u201d \u043d\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0443. \u041e\u043d \u043d\u0435 \u0443\u0447\u0430\u0441\u0442\u0432\u0443\u0435\u0442 \u0432 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u043b\u043e\u0433\u0438\u043a\u0438, \u043d\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0451 &#8212; \u0431\u0443\u0434\u044c \u0442\u043e \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u043b\u0438 \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u0432 Mermaid.<\/p>\n<p>\u041f\u043e \u0441\u0443\u0442\u0438, \u044d\u0442\u043e \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0441\u043b\u043e\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u0435\u043b\u0430\u0435\u0442 \u0441\u043b\u043e\u0436\u043d\u0443\u044e \u043a\u043e\u043d\u0435\u0447\u043d\u0443\u044e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u043d\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0437\u0440\u0430\u0447\u043d\u043e\u0439 \u0438 \u0443\u0434\u043e\u0431\u043d\u043e\u0439 \u0434\u043b\u044f \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f, \u043e\u0442\u043b\u0430\u0434\u043a\u0438 \u0438 \u043a\u043e\u043c\u043c\u0443\u043d\u0438\u043a\u0430\u0446\u0438\u0438 \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/mIARbPZ.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/mIARbPZ.png 780w,&#10;       https:\/\/i.imgur.com\/mIARbPZ.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p><a class=\"anchor\" name=\"mt20\" id=\"mt20\"><\/a><\/p>\n<h3>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 Sagas<\/h3>\n<p>\u041a\u0430\u043a \u043c\u044b \u0443\u0436\u0435 \u0437\u043d\u0430\u0435\u043c, \u0447\u0442\u043e \u0432\u043d\u0430\u0447\u0430\u043b\u0435 \u0443 \u043d\u0430\u0441 \u0438\u0434\u0435\u0442 ReceivePipe \u0442.\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0447\u0435\u0440\u0435\u0437 \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442 \u0438 \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0430\u043c \u043e\u043d \u043c\u0430\u043b\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0435\u043d.<\/p>\n<p>\u041a\u043b\u044e\u0447\u0435\u0432\u043e\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0442\u0443\u0442 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0443 Sagas \u0438\u043c\u0435\u0435\u0442\u0441\u044f CorrelationIdMessageFilter \u0432\u043d\u0443\u0442\u0440\u0438 ConsumePipe, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 ProxyContext \u0438 \u043f\u0440\u043e\u043a\u0438\u0434\u044b\u0432\u0430\u0435\u0442 \u0435\u0433\u043e \u0434\u0430\u043b\u044c\u0448\u0435 \u043f\u043e \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0443, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a CorrelatedSagaFilter.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/fbUeGgC.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/fbUeGgC.png 780w,&#10;       https:\/\/i.imgur.com\/fbUeGgC.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/duJMF3r.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/duJMF3r.png 780w,&#10;       https:\/\/i.imgur.com\/duJMF3r.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u043e\u0436\u043d\u043e \u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043d\u0430\u0447\u0430\u043b\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043d\u0430\u0448\u0435\u0439 Saga. \u0418 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0441 SagaRepository, \u0433\u0434\u0435 \u0435\u0441\u043b\u0438 \u043f\u0440\u043e\u0432\u0430\u043b\u0438\u0442\u0441\u044f \u0447\u0443\u0442\u044c \u0433\u043b\u0443\u0431\u0436\u0435 \u0442.\u0435 \u0447\u0435\u0440\u0435\u0437 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u044e &#8212; \u043c\u044b \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u043c EntityFrameworkSagaRepositoryContextFactory, \u0433\u0434\u0435 \u0443 \u043d\u0430\u0441 \u0441\u0442\u0430\u0440\u0442\u0443\u0435\u0442 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f \u0441 isolationLevel = ReadCommited.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/hmZc28J.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/hmZc28J.png 780w,&#10;       https:\/\/i.imgur.com\/hmZc28J.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/MRnBg2d.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/MRnBg2d.png 780w,&#10;       https:\/\/i.imgur.com\/MRnBg2d.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u044d\u0442\u043e \u0432\u0441\u0435 PipeLine, \u0442\u043e \u043c\u044b \u0432\u043a\u043e\u043d\u0446\u0435-\u043a\u043e\u043d\u0446\u043e\u0432 \u0441\u044e\u0434\u0430 \u043f\u043e\u0441\u043b\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0432\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u0438 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d Commit \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u043b\u0438\u0431\u043e Rollback<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0439 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438, \u0443 \u043d\u0430\u0441 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e pipeline \u0441 DbContextSagaRepositoryContext \u0441 SendSagaPipe<\/p>\n<p>\u0412 SendSagaPipe \u043c\u044b \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u0435\u043c\u0441\u044f \u0441 \u0442\u0430\u043a\u043e\u0439 \u0432\u0435\u0449\u044c\u044e \u043a\u0430\u043a policy. \u0415\u0441\u043b\u0438 \u0432\u043a\u0440\u0430\u0442\u0446\u0435 \u0442\u043e \u044d\u0442\u043e \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 Sagas. \u0412 \u043f\u0435\u0440\u0432\u0443\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043b\u0438 \u0437\u0430\u043f\u0438\u0441\u044c \u0441 \u0434\u0430\u043d\u043d\u043e\u0439 SagaInstance \u0432 \u0411\u0414 Saga \u0447\u0435\u0440\u0435\u0437 DbContextSagaRepository, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0432\u043a\u043b\u044e\u0447\u0435\u043d OptimisticLocking(\u0432 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435), \u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u0437\u0430\u043f\u0440\u043e\u0441 \u0441 SingleOrDefaultAsync \u043e\u0442 Ef Core, \u043d\u043e \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u043d\u0430\u0445\u043e\u0434\u0438\u0442 \u0442.\u043a \u043c\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u043d\u0430\u0448\u0443 Sagas\u2026<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/l569yx4.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/l569yx4.png 780w,&#10;       https:\/\/i.imgur.com\/l569yx4.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043c\u044b \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u043c \u043d\u043e\u0432\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0440\u0430\u043d\u0435\u0435 \u043d\u0435 \u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043b\u0430 \u0432 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0443 \u0411\u0414, \u0442\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f MissingPolicy \u0442.\u0435 MissingSagaPipe.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/2hJR1DF.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/2hJR1DF.png 780w,&#10;       https:\/\/i.imgur.com\/2hJR1DF.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p>\u041c\u044b \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u043c \u0432 \u0444\u0438\u043b\u044c\u0442\u0440 \u043c\u0430\u0448\u0438\u043d\u044b \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439, \u0433\u0434\u0435 \u0443 \u043d\u0430\u0441 \u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432(\u0432\u043c\u0435\u0441\u0442\u043e Pipes \u0442\u0435\u043f\u0435\u0440\u044c Behaviours), \u043d\u043e \u044d\u0442\u043e \u0432\u0441\u0435 \u0442\u043e\u0442 \u0436\u0435 \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u044b\u0439 \u043d\u0430\u043c Pipeline \u0432 \u0434\u0440\u0443\u0433\u043e\u0439 \u043e\u0431\u0435\u0440\u0442\u043a\u0435. \u0412\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u0438\u0432\u0435\u043d\u0442 \u0441 behaviourContext \u0438 \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u043c \u0432 \u044f\u0434\u0440\u043e \u043c\u0430\u0448\u0438\u043d\u044b \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 Saga \u0442.\u0435 MassTransitStateMachine.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/flMGBk4.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/flMGBk4.png 780w,&#10;       https:\/\/i.imgur.com\/flMGBk4.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p>\u0412\u043a\u043e\u043d\u0446\u0435 \u043a\u043e\u043d\u0446\u043e\u0432 \u043d\u0430\u043c \u043d\u0430\u0434\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c Accessor \u0442.\u0435 \u044d\u0442\u043e \u0442\u043e\u0442 \u0441\u043b\u043e\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0433\u043e\u0432\u043e\u0440\u0438\u0442 \u0433\u0434\u0435 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f state \u0438 \u043a\u0430\u043a \u0435\u0433\u043e \u0447\u0438\u0442\u0430\u0442\u044c\/\u043c\u0435\u043d\u044f\u0442\u044c. \u041c\u044b \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u043c InitialIfNullStateAccessor(\u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0438 \u0434\u0440\u0443\u0433\u0438\u0435, \u043d\u043e \u043d\u0435 \u043e \u043d\u0438\u0445).<\/p>\n<p>\u041d\u0430\u0448\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0440\u0430\u0432\u043d\u043e null, \u043e\u0442\u0441\u044e\u0434\u0430 \u043d\u0430\u0434\u043e \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c state machine instance \u0434\u043e \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f runtime<\/p>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0443\u0436\u0435 \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u0435\u043c\u0441\u044f \u0441 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438 State Machine, \u0430 \u044d\u0442\u043e Activity(\u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 TransitionActivity). \u041e\u0434\u0438\u043d \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u0432\u0430\u0436\u043d\u044b\u0445 \u0441\u043b\u043e\u0435\u0432 state machine \u0442.\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u0437\u0434\u0435\u0441\u044c \u0436\u0438\u0432\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430. Activities \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0442 \u0437\u0430 \u0448\u0430\u0433\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0432\u043d\u0443\u0442\u0440\u0438 state machine (behaviour pipeline).<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/bZmqAfI.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/bZmqAfI.png 780w,&#10;       https:\/\/i.imgur.com\/bZmqAfI.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p>\u041a\u0430\u0436\u0434\u0430\u044f Activity \u0434\u0435\u043b\u0430\u0435\u0442 Execute \u0432\u044b\u0437\u044b\u0432\u0430\u044f next, \u043b\u0438\u0431\u043e Faulted \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0438 (\u0438\u043b\u0438 \u043f\u0440\u043e\u043a\u0438\u0434\u044b\u0432\u0430\u044f).<\/p>\n<p>\u041c\u0435\u0442\u043e\u0434 Transition \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c(\u0440\u0430\u043d\u0435\u0435 \u043e\u0431\u0441\u0443\u0436\u0434\u0430\u043b\u0438 \u0447\u0442\u043e \u0443 State \u0435\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044b \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0435)<\/p>\n<ol>\n<li>\n<p>\u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f<\/p>\n<\/li>\n<li>\n<p>Leave \u0442.\u0435 \u0432\u044b\u0445\u043e\u0434 \u0438\u0437 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f<\/p>\n<\/li>\n<li>\n<p>BeforeEnter \u0442.\u0435 \u043b\u043e\u0433\u0438\u043a\u0430 \u043f\u0435\u0440\u0435\u0434 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u043e\u043c \u0432 \u043d\u043e\u0432\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435<\/p>\n<\/li>\n<li>\n<p>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f<\/p>\n<\/li>\n<li>\n<p>After Leave \u043b\u043e\u0433\u0438\u043a\u0430 \u043f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u0438\u0437 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p>Enter &#8212; \u0434\u043b\u044f \u0432\u0441\u0435\u0439 \u0438\u0435\u0440\u0430\u0440\u0445\u0438\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f<\/p>\n<\/li>\n<\/ol>\n<p>\u041a\u0430\u0436\u0434\u044b\u0439 TransitionTo \u043d\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0441\u0440\u0430\u0437\u0443, \u0430 \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0432 TransitionActivity. <\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/tCtjhT8.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/tCtjhT8.png 780w,&#10;       https:\/\/i.imgur.com\/tCtjhT8.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p>\u041e\u043d \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043c\u0435\u043d\u044f\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u0430 \u0434\u0435\u043b\u0430\u0435\u0442 \u0446\u0435\u043b\u044b\u0439 Lifesycle \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u0442.\u0435<\/p>\n<ol>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 Saga (Initial transition) null \u2192 Initially \u041a\u043e\u0433\u0434\u0430 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u043f\u0435\u0440\u0432\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435, \u0442\u043e \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f Saga, \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 Initially(\u0441\u043e\u0437\u0434\u0430\u043b\u0430\u0441\u044c Saga), \u0437\u0430\u0442\u0435\u043c \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u0432 Started<\/p>\n<\/li>\n<li>\n<p>\u041f\u0435\u0440\u0432\u044b\u0439 \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f Initially \u2192 Started \u041f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 Then(\u2026), \u0437\u0430\u043f\u0443\u0441\u043a TransitionActivity,\u0441\u043c\u0435\u043d\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043d\u0430 Started<\/p>\n<\/li>\n<li>\n<p>\u0414\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0438\u0435 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044b Started \u2192 Updated \u2192 Processing \u2192 Processed \u041a\u0430\u0436\u0434\u044b\u0439 \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 TransitionActivity \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u043b\u043d\u044b\u0439 lifecycle (leave &#8212; beforeEnter &#8212; enter &#8212; afterleave) \u0438 \u0432\u043a\u043e\u043d\u0446\u0435 \u043a\u043e\u043d\u0446\u043e\u0432 \u0444\u0438\u043a\u0441\u0430\u0446\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0432 Saga Storage<\/p>\n<\/li>\n<\/ol>\n<p>\u0412\u0441\u0435 \u043a\u0440\u0443\u0442\u0438\u0442\u0441\u044f \u0432 \u0446\u0438\u043a\u043b\u0435 \u0434\u043e \u0442\u0435\u0445 \u043f\u043e\u0440 \u043f\u043e\u043a\u0430 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430 \u043b\u043e\u0433\u0438\u043a\u0430 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u043e\u0432 \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u0430\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u043e\u0439 MassTransitStateMachine.<\/p>\n<p>\u0418 \u0437\u0430\u043a\u043e\u043c\u0438\u0447\u0435\u043d\u0430 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f.<\/p>\n<p><a class=\"anchor\" name=\"mt21\" id=\"mt21\"><\/a><\/p>\n<h3>\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438<\/h3>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0442\u044b \u043f\u0438\u0448\u0435\u0448\u044c During(Started, When(SomethingReceived)\u2026, \u0442\u044b \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0448\u044c \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f: \u0434\u043b\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f Started \u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f SomethingReceived \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f behavior (\u0446\u0435\u043f\u043e\u0447\u043a\u0430 \u0438\u0437 Then, TransitionTo \u0438 \u0442.\u0434.). \u0418\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u043e\u0442 behavior \u043f\u043e\u0442\u043e\u043c \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 behaviors.TryGetValue(\u2026) \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 Execute<\/p>\n<p>Initially &#8212; \u044d\u0442\u043e \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435, \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f (Initial).<\/p>\n<p>DuringAny &#8212; \u044d\u0442\u043e \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438, \u043e\u043d\u0438 \u043d\u0435 \u043b\u0435\u0436\u0430\u0442 \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f.<\/p>\n<p>BeforeEnter, Enter, AfterLeave &#8212; \u044d\u0442\u043e \u043e\u0431\u044b\u0447\u043d\u044b\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 MassTransit \u0441\u0430\u043c \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430\u0445 \u043c\u0435\u0436\u0434\u0443 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f\u043c\u0438.<\/p>\n<p>\u041a\u043e\u0433\u0434\u0430 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 TransitionTo(Started), \u0432\u043d\u0443\u0442\u0440\u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0432\u0440\u043e\u0434\u0435 Started.BeforeEnter, \u0438 \u0435\u0441\u043b\u0438 \u0442\u044b \u0433\u0434\u0435-\u0442\u043e \u043e\u043f\u0438\u0441\u0430\u043b When(Started.BeforeEnter), \u0434\u043b\u044f \u043d\u0435\u0433\u043e \u0442\u043e\u0436\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d behavior.<\/p>\n<p>\u0412 \u0438\u0442\u043e\u0433\u0435 Execute \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0435\u0441\u043b\u0438 \u0434\u043b\u044f \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043d\u0430\u0439\u0434\u0435\u043d behavior. \u041e\u043d \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043b\u0438\u0431\u043e \u043f\u0440\u044f\u043c\u043e \u0432 \u0442\u0435\u043a\u0443\u0449\u0435\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 (\u0447\u0435\u0440\u0435\u0437 During\/Initially), \u043b\u0438\u0431\u043e \u043d\u0430\u0439\u0434\u0435\u043d \u0447\u0435\u0440\u0435\u0437 fallback (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0438\u0437 DuringAny).<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/FPX9i6j.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/FPX9i6j.png 780w,&#10;       https:\/\/i.imgur.com\/FPX9i6j.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/xMgqdFP.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/xMgqdFP.png 780w,&#10;       https:\/\/i.imgur.com\/xMgqdFP.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p>\u0420\u0430\u0437\u043d\u0438\u0446\u0430 \u0442\u0443\u0442 \u0432 \u0432\u044b\u0437\u043e\u0432\u0430\u0445 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u043d\u0430\u043b\u0438\u0447\u0438\u0438 payload<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/tZAoVTY.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/tZAoVTY.png 780w,&#10;       https:\/\/i.imgur.com\/tZAoVTY.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/9YTbCYz.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/9YTbCYz.png 780w,&#10;       https:\/\/i.imgur.com\/9YTbCYz.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p><a class=\"anchor\" name=\"mt22\" id=\"mt22\"><\/a><\/p>\n<h3>\u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044c Saga \u043a\u0430\u043a \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430<\/h3>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0441\u0430\u0433\u0438 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u0442\u0443\u043f\u0430\u044e\u0442 \u0447\u0435\u0440\u0435\u0437 \u0431\u0440\u043e\u043a\u0435\u0440, \u043f\u0440\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f MassTransit \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0441\u0430\u0433\u0443 \u043f\u043e CorrelationId \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 behavior \u0434\u043b\u044f \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f.<\/p>\n<p>\u0415\u0441\u043b\u0438 \u0441\u0435\u0440\u0432\u0438\u0441 \u043f\u0430\u0434\u0430\u0435\u0442 \u0434\u043e \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 (ack), \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u044c \u0438 \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043e \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e \u043f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c MassTransit \u043d\u0435 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u043e\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 behavior, \u0430 \u0432\u0441\u0435\u0433\u0434\u0430 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0437\u0430\u043d\u043e\u0432\u043e, \u0438\u0441\u0445\u043e\u0434\u044f \u0438\u0437 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441\u0430\u0433\u0438 \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>\u041f\u0440\u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u0445 \u0441 \u0442\u0435\u043c \u0436\u0435 CorrelationId \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0432\u0441\u0435\u0433\u0434\u0430 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0441 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0451\u043d\u043d\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f. \u0415\u0441\u043b\u0438 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0438\u0445 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u043e\u0432 \u043d\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043e (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043e\u0441\u0442\u0438\u0433\u043d\u0443\u0442 \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 state), \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043e \u0438\u043b\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043e \u043a\u0430\u043a \u043d\u0435 \u0438\u043c\u0435\u044e\u0449\u0435\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f.<\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0441\u0430\u0433\u0438 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c CurrentState \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u0430 \u043d\u0435 \u0447\u0430\u0441\u0442\u0438\u0447\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u043c\u0438 \u0448\u0430\u0433\u0430\u043c\u0438 \u0432\u043d\u0443\u0442\u0440\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/5ezESjO.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/5ezESjO.png 780w,&#10;       https:\/\/i.imgur.com\/5ezESjO.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p><a class=\"anchor\" name=\"mt23\" id=\"mt23\"><\/a><\/p>\n<h3>\u041b\u0443\u0447\u0448\u0438\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 Sagas Orchestration<\/h3>\n<p>\u041c\u044b \u0443\u0432\u0438\u0434\u0435\u043b\u0438 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e Sagas \u0432 MassTransit, \u043e\u043d\u0430 \u043d\u0438 \u043a\u0430\u043f\u043b\u0438 \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u0430 \u0441\u0430\u043c\u0430 \u0438\u0434\u0435\u044f \u043f\u0440\u043e\u0441\u0442\u0430\u044f, \u043e\u0442\u0441\u044e\u0434\u0430 \u0434\u043b\u044f \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0431\u0443\u0434\u0435\u0442 \u0443\u043c\u0435\u0441\u0442\u043d\u044b\u043c \u0432\u0437\u0433\u043b\u044f\u043d\u0443\u0442\u044c \u043a\u0430\u043a \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u0445.<\/p>\n<p>\u0412 \u0431\u043e\u043b\u0435\u0435 \u043b\u0435\u0433\u043a\u0438\u0439 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043f\u0440\u0438\u043c\u0435\u0440 Sagas \u043e\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u044b devmentors. \u041f\u0440\u043e\u0449\u0435 \u0433\u043e\u0432\u043e\u0440\u044f \u044d\u0442\u043e \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0430\u044f IT-\u043a\u043e\u043c\u043f\u0430\u043d\u0438\u044f \u0438 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0438\u0437 \u041f\u043e\u043b\u044c\u0448\u0438, \u0433\u043e\u0440\u043e\u0434\u0430 \u041a\u0440\u0430\u043a\u043e\u0432.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/qe4ZWhs.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/qe4ZWhs.png 780w,&#10;       https:\/\/i.imgur.com\/qe4ZWhs.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p>\u0418\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 Sagas \u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043b\u0430 \u0432 \u043e\u0434\u043d\u043e\u043c \u0438\u0437 \u0440\u043e\u043b\u0438\u043a\u043e\u0432 \u043d\u0430 \u044e\u0442\u0443\u0431\u0435 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 DNC-DShop, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u0441\u0435\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0432 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435. \u0412\u043d\u0443\u0442\u0440\u0438, \u0434\u043b\u044f \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b Sagas \u0431\u044b\u043b\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c \u201cChronicle\u201d. <\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/FNLvWQu.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/FNLvWQu.png 780w,&#10;       https:\/\/i.imgur.com\/FNLvWQu.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/YKT69ja.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/YKT69ja.png 780w,&#10;       https:\/\/i.imgur.com\/YKT69ja.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p>\u0418 \u0447\u0442\u043e\u0431 \u043b\u0443\u0447\u0448\u0435 \u043f\u043e\u043d\u044f\u0442\u044c \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0441\u0430\u0433\u0438 \u043e\u043d\u0438 \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u0438\u043c\u0435\u043d\u043d\u043e \u043f\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0443 manual control flow engine \u0442.\u0435 \u0442\u044b \u0441\u0430\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u0443\u0435\u0448\u044c:<\/p>\n<ol>\n<li>\n<p>\u041a\u043e\u0433\u0434\u0430 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f Saga<\/p>\n<\/li>\n<li>\n<p>\u041a\u0430\u043a \u0438\u0449\u0435\u0442\u0441\u044f Saga<\/p>\n<\/li>\n<li>\n<p>\u043a\u0430\u043a \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f handlers<\/p>\n<\/li>\n<li>\n<p>\u043a\u0430\u043a \u0434\u0435\u043b\u0430\u044e\u0442\u0441\u044f compensations<\/p>\n<\/li>\n<\/ol>\n<p>\u041f\u0443\u0441\u0442\u044c \u0432\u0430\u0441 \u043d\u0435 \u0441\u0431\u0438\u0432\u0430\u0435\u0442 \u0441\u0442\u043e\u043b\u043a\u0443 \u0447\u0442\u043e Chronicle \u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u0438\u0442 \u043d\u0435\u043a\u043e\u0435\u043c\u0443 snatch.dev github \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0443, \u0432\u0435\u0434\u044c \u044d\u0442\u043e \u043f\u043e \u0441\u0443\u0442\u0438 \u0441\u0432\u043e\u0435\u0439 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0430\u043a\u043a\u0430\u0443\u043d\u0442 \u0434\u043b\u044f \u043b\u0438\u0431 DevMentors, \u0430 \u0442\u0430\u043a \u0436\u0435 \u0443 \u043d\u0438\u0445 \u043e\u0434\u043d\u043e\u0438\u043c\u0435\u043d\u043d\u044b\u0439 Github Account, \u0433\u0434\u0435 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0442\u0430 \u0436\u0435 \u043b\u0438\u0431\u0430 Trill.Saga, \u0433\u0434\u0435 \u0438 \u0432\u043d\u0443\u0442\u0440\u0438 \u043d\u0435\u0451 Chronicle \u0442\u0430\u043a \u0436\u0435.<\/p>\n<p>\u041a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u0438\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439 \u044f \u043d\u0435 \u0432\u0438\u0436\u0443 \u0441\u043c\u044b\u0441\u043b\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c. \u0412\u0441\u0435 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e &#8212; \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 \u0431\u0440\u043e\u043a\u0435\u0440, \u0438\u0445 \u0434\u0435\u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f, \u0432\u044b\u0437\u043e\u0432 \u043d\u0443\u0436\u043d\u043e\u0433\u043e Event\u2019\u0430 Saga. \u042d\u0442\u043e \u0442\u0430 \u0436\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u0430\u044f \u043e\u0440\u043a\u0435\u0441\u0442\u0440\u0430\u0446\u0438\u044f, \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0447\u0443\u0442\u043a\u0430 \u0438\u043d\u0430\u0447\u0435. \u041e\u043d\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u044e Sagas, \u043d\u043e \u043c\u0435\u043d\u044c\u0448\u0435 \u043e\u0431\u0432\u044f\u0437\u043e\u043a \u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438. \u0422\u0440\u0443\u0434\u043d\u043e\u0441\u0442\u0435\u0439 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u0443\u0442\u044c \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e.<\/p>\n<p>\u041f\u043e\u0447\u0435\u043c\u0443 \u0442\u0430\u043a \u0436\u0435 \u0438\u0445 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0437\u0430\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u0435\u0442 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u044f? \u0421\u0440\u0435\u0434\u0438 \u043d\u0438\u0445 \u0435\u0441\u0442\u044c ex-Microsoft MVP &#8212; Piotor Gankiewicz. \u0422\u0430\u043b\u0430\u043d\u0442\u043b\u0438\u0432\u044b\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0438 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u043e\u0440.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/dTOY6RM.jpeg\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/dTOY6RM.jpeg 780w,&#10;       https:\/\/i.imgur.com\/dTOY6RM.jpeg 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p><a class=\"anchor\" name=\"mt24\" id=\"mt24\"><\/a><\/p>\n<h2>\u041f\u0440\u0438\u043c\u0435\u0440 \u043d\u0430 NServiceBus<\/h2>\n<p>\u0420\u0430\u043d\u0435\u0435 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 Sagas \u043d\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0435 DevMentors \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c Chronicle, \u0433\u0434\u0435 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0442 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043d\u044b\u0435 \u043e\u0431\u0432\u044f\u0437\u043a\u0438, \u0438 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0430\u043a\u0446\u0435\u043d\u0442 \u0441\u0434\u0435\u043b\u0430\u043d \u043d\u0430 \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u043e\u0432 \u0440\u0430\u0431\u043e\u0442\u044b. \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043a \u0440\u0435\u0448\u0435\u043d\u0438\u044e enterprise-\u0443\u0440\u043e\u0432\u043d\u044f &#8212; NServiceBus, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u043d\u043e \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u044c \u043f\u043e \u0437\u043d\u0430\u0447\u0438\u043c\u043e\u0441\u0442\u0438 \u0438 \u0437\u0440\u0435\u043b\u043e\u0441\u0442\u0438 \u0441 MassTransit. \u041f\u0440\u0438 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u0438\u0438 \u044d\u0442\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0437\u0430\u043c\u0435\u0442\u043d\u043e, \u0447\u0442\u043e \u043e\u043d\u0430 \u043c\u0435\u043d\u0435\u0435 \u201c\u0433\u0438\u0431\u043a\u0430\u044f\u201d \u0438 \u0434\u0435\u043a\u043b\u0430\u0440\u0430\u0442\u0438\u0432\u043d\u0430\u044f \u043f\u043e \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044e \u0441 MassTransit \u0438 \u0435\u0433\u043e SagaStateMachine. \u0412 NServiceBus \u043c\u043e\u0434\u0435\u043b\u044c Sagas \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u0438\u0437\u0435\u043c\u043b\u0451\u043d\u043d\u0430\u044f \u0438 \u0441\u0442\u0440\u043e\u0433\u0430\u044f: \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0431\u043b\u0438\u0436\u0435 \u043a \u0443\u0440\u043e\u0432\u043d\u044e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0438 \u044f\u0432\u043d\u043e\u0433\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c, \u0431\u0435\u0437 \u0432\u044b\u0441\u043e\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u043e\u0439 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u0438 state machine, \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u043d\u043e\u0439 \u0434\u043b\u044f MassTransit.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/S4evPiD.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/S4evPiD.png 780w,&#10;       https:\/\/i.imgur.com\/S4evPiD.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/zCVHsqF.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/zCVHsqF.png 780w,&#10;       https:\/\/i.imgur.com\/zCVHsqF.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/0bL7HFF.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/0bL7HFF.png 780w,&#10;       https:\/\/i.imgur.com\/0bL7HFF.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/LcUWT6u.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/LcUWT6u.png 780w,&#10;       https:\/\/i.imgur.com\/LcUWT6u.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/eeAT5Gr.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/eeAT5Gr.png 780w,&#10;       https:\/\/i.imgur.com\/eeAT5Gr.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<p><a class=\"anchor\" name=\"mt25\" id=\"mt25\"><\/a><\/p>\n<h3>\u041a\u0430\u043a\u043e\u0439 \u0432\u044b\u0432\u043e\u0434 \u043a\u0430\u0441\u0430\u0435\u043c\u043e Sagas?<\/h3>\n<p>Saga Orchestration \u0438\u0437 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438 = Message broker + state + correlation + workflow orchestration + compensation + eventual consistency.<\/p>\n<ol>\n<li>\n<p>Saga \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043f\u043e\u0432\u0435\u0440\u0445 message broker\u2019a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0441\u043d\u043e\u0432\u043e\u0439 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u043e\u0433\u043e \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043c\u0435\u0436\u0434\u0443 \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c\u0438.<\/p>\n<\/li>\n<li>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f event-driven \u0438\u043b\u0438 command-driven \u043c\u043e\u0434\u0435\u043b\u044c, \u0433\u0434\u0435 events &#8212; \u044d\u0442\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u0444\u0438\u043a\u0441\u0438\u0440\u0443\u044e\u0449\u0438\u0435 \u0444\u0430\u043a\u0442 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0447\u0442\u043e-\u0442\u043e \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u043e, \u0430 commands &#8212; \u044d\u0442\u043e \u043a\u043e\u043c\u0430\u043d\u0434\u044b, \u0438\u043d\u0438\u0446\u0438\u0438\u0440\u0443\u044e\u0449\u0438\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0442.\u0435 CQRS \u0438 Sagas \u0441\u0432\u044f\u0437\u0430\u043d\u044b<\/p>\n<\/li>\n<li>\n<p>Saga \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f stateful workflow \u0438 \u0445\u0440\u0430\u043d\u0438\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0431\u0438\u0437\u043d\u0435\u0441-\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u043c\u0435\u0436\u0434\u0443 \u0448\u0430\u0433\u0430\u043c\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p>\u041a\u043e\u0440\u0440\u0435\u043b\u044f\u0446\u0438\u044f \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0441\u0432\u044f\u0437\u044c \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0441 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u0441\u0430\u0433\u043e\u0439, \u0431\u0435\u0437 \u0447\u0435\u0433\u043e \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c, \u043a\u0430\u043a\u043e\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c.<\/p>\n<\/li>\n<li>\n<p>\u041e\u0440\u043a\u0435\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e Saga \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u0435\u0442 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u043e\u0440\u043e\u043c \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0448\u0430\u0433\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p>\u0412 \u0441\u0438\u0441\u0442\u0435\u043c\u0435 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0442 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u0435 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438, \u0438 \u0432\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u0448\u0430\u0433 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043a\u0430\u043a \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0430\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u0430\u044f \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f \u0441 \u043c\u043e\u0434\u0435\u043b\u044c\u044e eventual consistency.<\/p>\n<\/li>\n<li>\n<p>\u041a\u043e\u043c\u043f\u0435\u043d\u0441\u0430\u0446\u0438\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0448\u0430\u0433\u0430, \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0442\u0441\u044f \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u0435 \u043a\u043e\u043c\u043f\u0435\u043d\u0441\u0438\u0440\u0443\u044e\u0449\u0438\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f, \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c\u044b\u0435 \u0432\u0440\u0443\u0447\u043d\u0443\u044e.<\/p>\n<\/li>\n<li>\n<p>Idempotency \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u0434\u043b\u044f \u0447\u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u044b optimistic concurrency control, pessimistic locking \u0438\u043b\u0438 concurrency tokens.<\/p>\n<\/li>\n<li>\n<p>Retry \u0438 fault handling \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u044e\u0442 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043f\u0440\u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u043e\u0448\u0438\u0431\u043a\u0430\u0445, \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0443 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0432 DLQ \u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u0432 compensation \u043f\u0440\u0438 \u0444\u0430\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u043e\u0448\u0438\u0431\u043a\u0430\u0445.<\/p>\n<\/li>\n<li>\n<p>Persisted workflow state \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 Saga \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0432\u043e \u0432\u043d\u0435\u0448\u043d\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435, \u043e\u0431\u044b\u0447\u043d\u043e \u0432 \u0431\u0430\u0437\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u0434\u043b\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0438 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430. <\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/HLOjKy1.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/HLOjKy1.png 780w,&#10;       https:\/\/i.imgur.com\/HLOjKy1.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<\/li>\n<\/ol>\n<p><a class=\"anchor\" name=\"mt26\" id=\"mt26\"><\/a><\/p>\n<h3>\u041f\u043e\u0434\u0432\u0435\u0434\u0435\u043c \u0438\u0442\u043e\u0433\u0438<\/h3>\n<p>\u041a\u0430\u043a \u043c\u044b \u0443\u0432\u0438\u0434\u0435\u043b\u0438, MassTransit \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c. \u041e\u043d \u0433\u0438\u0431\u043a\u0438\u0439, \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u043c\u044b\u0439 \u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0434\u043b\u044f enterprise-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438. \u041e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u0437\u0430\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u0435\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f Sagas. \u041e\u043d\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430 \u043d\u0430 \u0432\u044b\u0441\u043e\u043a\u043e\u043c \u0443\u0440\u043e\u0432\u043d\u0435 \u0438 \u0432\u044b\u0433\u043e\u0434\u043d\u043e \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f \u043e\u0442 \u043c\u043d\u043e\u0433\u0438\u0445 \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432 \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u043c\u0443 DSL, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0431\u0438\u0437\u043d\u0435\u0441-\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0432. \u0422\u0430\u043a\u0436\u0435 \u0432 MassTransit \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u043e\u0432 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043d\u043e\u0433\u043e \u0443\u0440\u043e\u0432\u043d\u044f: pipeline-\u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432, \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0431\u0440\u043e\u043a\u0435\u0440\u043e\u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0438 \u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u044b\u0445 persistence-\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449. \u0424\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0431\u0435\u0440\u0451\u0442 \u043d\u0430 \u0441\u0435\u0431\u044f \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0443 \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0438\u0442\u044c\u0441\u044f \u043d\u0430 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0435 \u0438 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0439 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438. \u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u044f \u0441 \u0432\u0435\u0440\u0441\u0438\u0438 8.0.0 \u0447\u0430\u0441\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0441\u0442\u0430\u043b\u0430 \u043f\u043b\u0430\u0442\u043d\u043e\u0439, MassTransit \u043f\u043e-\u043f\u0440\u0435\u0436\u043d\u0435\u043c\u0443 \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u043e\u0434\u043d\u0438\u043c \u0438\u0437 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0441\u0438\u043b\u044c\u043d\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439 \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u0445 \u0438 \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u0432\u0430\u0436\u043d\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c, \u0447\u0442\u043e \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438, \u043b\u0435\u0436\u0430\u0449\u0438\u0435 \u0432 \u0435\u0433\u043e \u043e\u0441\u043d\u043e\u0432\u0435, \u0432\u043a\u043b\u044e\u0447\u0430\u044f Sagas, \u043e\u043f\u0438\u0440\u0430\u044e\u0442\u0441\u044f \u043d\u0430 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u044b\u0435 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u044b, \u043e\u0434\u043d\u0430\u043a\u043e \u0434\u043e\u0432\u0435\u0434\u0435\u043d\u044b \u0434\u043e \u0443\u0440\u043e\u0432\u043d\u044f \u0437\u0440\u0435\u043b\u043e\u0433\u043e \u0438 \u0438\u043d\u0436\u0435\u043d\u0435\u0440\u043d\u043e \u0432\u044b\u0432\u0435\u0440\u0435\u043d\u043d\u043e\u0433\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u0440\u0430\u0431\u043e\u0442\u0435 \u041a\u0440\u0438\u0441\u0430 \u041f\u0430\u0442\u0435\u0440\u0441\u043e\u043d\u0430 \u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u0441\u0442\u0432\u0430.<\/p>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u0432\u0441\u0435, \u0441\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \ud83d\ude42<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/i.imgur.com\/kY3ElEJ.png\" alt=\"\u041f\u0440\u0438\u043c\u0435\u0440\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/i.imgur.com\/kY3ElEJ.png 780w,&#10;       https:\/\/i.imgur.com\/kY3ElEJ.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0440\u0438\u043c\u0435\u0440<\/figcaption><\/div>\n<\/figure>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1033712\/\">https:\/\/habr.com\/ru\/articles\/1033712\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u041f\u0440\u0438\u0432\u0435\u0442! \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 MassTransit &#8212; \u043e\u0434\u043d\u043e\u0439 \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u0437\u0440\u0435\u043b\u044b\u0445 .NET-\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c, \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0431\u0440\u043e\u043a\u0435\u0440\u0430\u043c\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u043e\u0432 \u0432\u0440\u043e\u0434\u0435 Saga \u0438 Consumer Pipeline.\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0432\u044b \u043d\u0430\u0447\u043d\u0451\u0442\u0435 \u0447\u0438\u0442\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u044c\u044e, \u0445\u043e\u0447\u0443 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0440\u0435\u043c\u0430\u0440\u043a\u0443: \u044d\u0442\u043e \u043c\u043e\u044f \u043f\u0435\u0440\u0432\u0430\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u044f, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u043e\u0448\u0443 \u043e\u0442\u043d\u0435\u0441\u0442\u0438\u0441\u044c \u0441 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435\u043c. \u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0441\u044f \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0441\u043b\u043e\u0436\u043d\u044b\u043c, \u0430 \u0435\u0433\u043e \u0440\u0430\u0437\u0431\u043e\u0440 \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b.\u0421\u0442\u0430\u0442\u044c\u044f, \u0432\u0435\u0440\u043e\u044f\u0442\u043d\u043e, \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u043e \u0434\u043e\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0438 \u0443\u0442\u043e\u0447\u043d\u044f\u0442\u044c\u0441\u044f \u043f\u043e \u043c\u0435\u0440\u0435 \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u044b\u0445 \u043f\u0440\u0430\u0432\u043e\u043a. \u0412 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0442\u0430\u043a\u043e\u0433\u043e \u0433\u043b\u0443\u0431\u043e\u043a\u043e\u0433\u043e \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0441\u043a\u043e\u0440\u0435\u0435 \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u043c\u0438 \u0432\u044b\u0432\u043e\u0434\u0430\u043c\u0438, \u043d\u043e \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0431\u044b\u0432\u0430\u0435\u0442 \u043d\u0435\u043f\u0440\u043e\u0441\u0442\u043e \u0441\u0440\u0430\u0437\u0443 \u0438\u0437\u043b\u043e\u0436\u0438\u0442\u044c \u0432\u0441\u0451 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043e. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u043c\u0435\u0441\u0442\u0430\u0445 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u0430 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u0443\u043c\u0431\u0443\u0440\u043d\u043e\u0441\u0442\u044c, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u044f \u043f\u043e\u0441\u0442\u0430\u0440\u0430\u044e\u0441\u044c \u0441\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0435\u043c \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c.\u0411\u044b\u0441\u0442\u0440\u044b\u0435 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044b\u041f\u043e\u0447\u0435\u043c\u0443 MassTransit \u0431\u044b\u0432\u0430\u0435\u0442 \u0441\u043b\u043e\u0436\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u044c\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0440\u0438\u0447\u0438\u043d\u044b \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438\u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u0430\u044f \u0438\u0434\u0435\u044f: PipelineGreenPipes \u0441\u0442\u0440\u043e\u0438\u0442\u0441\u044f \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u0445\u041f\u0435\u0440\u0435\u0445\u043e\u0434 \u043a \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0435 MassTransit\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 DI-\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0432 MassTransit\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f MassTransit: \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f vs \u0440\u0443\u0447\u043d\u0430\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044fConfiguration \u0438 ConfiguratorsRuntime-\u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 MassTransit\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438 \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044fPipeline \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 MassTransitChannelExecutorPipeline \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 MassTransitSagasSagaStateMachine \u0438 FSMSagas \u0432\u043d\u0443\u0442\u0440\u0438 MassTransitSagaStateMachineStates \u0432 SagaStateMachineSagaStateMachine \u0438 Graphs\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 Sagas\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438\u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044c Saga \u043a\u0430\u043a \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430\u041b\u0443\u0447\u0448\u0438\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 Sagas Orchestration\u041f\u0440\u0438\u043c\u0435\u0440 \u043d\u0430 NServiceBus\u041a\u0430\u043a\u043e\u0439 \u0432\u044b\u0432\u043e\u0434 \u043a\u0430\u0441\u0430\u0435\u043c\u043e Sagas?\u041f\u043e\u0434\u0432\u0435\u0434\u0435\u043c \u0438\u0442\u043e\u0433\u0438\u0415\u0441\u043b\u0438 \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u0431\u043e\u043b\u0435\u0435 \u0433\u043b\u0443\u0431\u043e\u043a\u043e\u0433\u043e \u0440\u0430\u0437\u0431\u043e\u0440\u0430 \u0441 \u043a\u043e\u0434\u043e\u043c \u0438 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0435\u0439 \u043f\u043e \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0430\u043c, \u0443 \u043c\u0435\u043d\u044f \u0435\u0441\u0442\u044c \u0438 \u0432\u0438\u0434\u0435\u043e\u0440\u0430\u0437\u0431\u043e\u0440 \u043d\u0430 YouTube. \u0417\u0434\u0435\u0441\u044c \u0436\u0435 &#8212; \u043a\u0440\u0430\u0442\u043a\u0430\u044f, \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u0434\u043b\u044f \u0442\u0435\u0445, \u043a\u0442\u043e \u0445\u043e\u0447\u0435\u0442 \u043f\u043e\u043d\u044f\u0442\u044c \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u044b\u0435 \u0438\u0434\u0435\u0438 \u0431\u0435\u0437 \u043f\u043e\u0433\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0432 50+ \u043c\u0438\u043d\u0443\u0442 \u0432\u0438\u0434\u0435\u043e.\u041f\u043e\u0447\u0435\u043c\u0443 MassTransit \u0431\u044b\u0432\u0430\u0435\u0442 \u0441\u043b\u043e\u0436\u043d\u043e \u043f\u043e\u043d\u044f\u0442\u044cMassTransit \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0443\u0436\u0435 \u0431\u043e\u043b\u0435\u0435 15 \u043b\u0435\u0442. \u042d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043b\u0430\u0441\u044c \u0435\u0449\u0451 \u0432\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0430 \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e .NET Framework &#8212; \u0437\u0430\u0434\u043e\u043b\u0433\u043e \u0434\u043e \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044f CoreCLR \u0438 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0433\u043e .NET.\u041f\u0440\u0438\u043c\u0435\u0440\u0410\u0432\u0442\u043e\u0440 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 &#8212; Chris Patterson, Microsoft MVP \u0438 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043b MassTransit \u043a\u0430\u043a \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 abstraction layer \u043d\u0430\u0434 \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u0430\u043c\u0438 (RabbitMQ, Azure Service Bus, Amazon SQS \u0438 \u0434\u0440.).\u041f\u0440\u0438\u043c\u0435\u0440\u041f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u0437\u043d\u0430\u043a\u043e\u043c\u0441\u0442\u0432\u0435 \u043a\u043e\u0434\u043e\u0432\u0430\u044f \u0431\u0430\u0437\u0430 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u043f\u0435\u0440\u0435\u0433\u0440\u0443\u0436\u0435\u043d\u043d\u043e\u0439. \u041d\u043e \u043f\u0440\u0438\u0447\u0438\u043d\u0430 \u043d\u0435 \u0432 \u0432\u043e\u0437\u0440\u0430\u0441\u0442\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0430 \u0432 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u043e\u0439 \u043d\u0430\u0441\u044b\u0449\u0435\u043d\u043d\u043e\u0441\u0442\u0438.\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0440\u0438\u0447\u0438\u043d\u044b \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438 :\u0411\u043e\u043b\u044c\u0448\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u043e\u0432 MassTransit \u0430\u043a\u0442\u0438\u0432\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442: Pipeline, Observer, Visitor, State, Finite State Machine(FSM) \u0438 \u0442\u0434\u2026 \u0422\u043e \u0435\u0441\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 &#8212; \u044d\u0442\u043e \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u201c\u043e\u0431\u0451\u0440\u0442\u043a\u0430 \u043d\u0430\u0434 RabbitMQ\u201d, \u0430 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 framework \u0441 \u0431\u043e\u0433\u0430\u0442\u043e\u0439 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0439 \u043c\u043e\u0434\u0435\u043b\u044c\u044e.\u0413\u043b\u0443\u0431\u043e\u043a\u043e\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 generics \u041f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u0441\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0441\u0442\u0440\u043e\u0438\u0442\u0441\u044f \u0432\u043e\u043a\u0440\u0443\u0433 T:ConsumeContext&lt;T&gt;ConsumerConsumeContext&lt;TConsumer, TMessage&gt;\u0422\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u043d\u043e-\u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0447\u043d\u0430\u044f \u043b\u043e\u0433\u0438\u043a\u0430 MassTransit \u0441\u0442\u0430\u0440\u0430\u0435\u0442\u0441\u044f \u0431\u044b\u0442\u044c \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u043c, \u043d\u043e \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u0430 \u0432\u0441\u0451 \u0440\u0430\u0432\u043d\u043e \u043f\u0440\u043e\u043d\u0438\u043a\u0430\u044e\u0442 \u0432\u043d\u0443\u0442\u0440\u044c \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b.\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 RabbitMQ:\u043e\u0434\u043d\u043e TCP-\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e channels;channels \u043d\u0435\u043b\u044c\u0437\u044f \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e \u0431\u0435\u0437 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f;\u043a\u043b\u0438\u0435\u043d\u0442 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0430\u043a\u043a\u0443\u0440\u0430\u0442\u043d\u043e\u0433\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f concurrency, \u0438\u043d\u0430\u0447\u0435 \u043c\u043e\u0436\u043d\u043e \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u0442\u044c\u0441\u044f \u0441 \u043d\u0430\u0440\u0443\u0448\u0435\u043d\u0438\u0435\u043c AMQP framing.\u0418\u043c\u0435\u043d\u043d\u043e \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 RabbitMQ Transport \u0435\u0441\u0442\u044c \u0442\u0430\u043a\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043a\u0430\u043a ChannelExecutor, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u0432\u044b\u0433\u043b\u044f\u0434\u044f\u0442 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u043c\u0438: \u043e\u043d\u0438 \u043f\u043e\u043c\u043e\u0433\u0430\u044e\u0442 \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c channel \u0438 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0442\u0430\u043c, \u0433\u0434\u0435 \u044d\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043eSagaStateMachine \u0438 \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u044b\u0435 \u0433\u0440\u0430\u0444\u044b \u041a\u043e\u0433\u0434\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0432\u043f\u0435\u0440\u0432\u044b\u0435 \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442 SagaStateMachine, \u0433\u0440\u0430\u0444\u044b \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u043e\u0432 \u043c\u043e\u0433\u0443\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043a\u0430\u043a \u0447\u0430\u0441\u0442\u044c runtime-\u043c\u0430\u0433\u0438\u0438.\u041d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u044d\u0442\u043e \u0441\u043a\u043e\u0440\u0435\u0435 \u0434\u0435\u043a\u043b\u0430\u0440\u0430\u0442\u0438\u0432\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442:\u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f\u0441\u043e\u0431\u044b\u0442\u0438\u044f\u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044b\u0413\u0440\u0430\u0444\u044b \u043d\u0443\u0436\u043d\u044b \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u0434\u043b\u044f \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u0430\u043d\u0430\u043b\u0438\u0437\u0430, \u0430 \u043d\u0435 \u043a\u0430\u043a \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 runtime-\u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f.[HttpGet(&#171;graph\/edges&#187;)]    public IActionResult GetGraphEdges()    {        var graph = _machine.GetGraph();        var sb = new StringBuilder();        sb.AppendLine(&#171;stateDiagram-v2&#8243;);        foreach (var edge in graph.Edges)        {            var from = edge.From.Title;            var to = edge.To.Title;            sb.AppendLine($&#187;{from} &#8212;&gt; {to}&#187;);        }        return Content(sb.ToString(), &#171;text\/plain&#187;);    }[HttpGet(&#171;graph\/vertices&#187;)]    public IActionResult GetGraphVertices()    {        var graph = _machine.GetGraph();        var sb = new StringBuilder();        sb.AppendLine(&#171;stateDiagram-v2&#8243;);        foreach (var vertex in graph.Vertices)        {            sb.AppendLine($&#187;state {vertex.Title}&#187;);        }        return Content(sb.ToString(), &#171;text\/plain&#187;);    }\u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u0430\u044f \u0438\u0434\u0435\u044f: PipelineMassTransit \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0441\u0442\u0440\u043e\u0438\u043b\u0441\u044f \u043f\u043e\u0432\u0435\u0440\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 GreenPipes, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u043b\u0430 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u044e\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443 Pipeline. \u0412 \u043d\u043e\u0432\u044b\u0445 \u0432\u0435\u0440\u0441\u0438\u044f\u0445 MassTransit GreenPipes \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043a\u0430\u043a \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0430\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c &#8212; \u0435\u0451 \u043a\u043e\u0434 \u0431\u044b\u043b \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u043d \u0432 \u0441\u0430\u043c MassTransit. \u042d\u0442\u043e \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u043e \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e GreenPipes \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0430 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0437\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u043c\u0438 \u044d\u043a\u043e\u0441\u0438\u0441\u0442\u0435\u043c\u044b MassTransit, \u0430 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043d\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u043b\u0438 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0430.\u041d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u0432 \u043e\u0441\u043d\u043e\u0432\u0435 MassTransit \u043b\u0435\u0436\u0438\u0442 \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u044b\u0439 \u043f\u0430\u0442\u0442\u0435\u0440\u043d Pipes &amp; Filters, \u043d\u043e \u044d\u0442\u043e \u043d\u0435 \u0441\u043e\u0432\u0441\u0435\u043c \u0442\u0430\u043a.\u041f\u0440\u0438\u043c\u0435\u0440\u041a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0439 Pipes &amp; Filters \u0445\u043e\u0440\u043e\u0448\u043e \u0437\u043d\u0430\u043a\u043e\u043c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u043e Bash-\u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440\u0430\u043c, \u0433\u0434\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0440\u0430\u0431\u043e\u0442\u044b \u043e\u0434\u043d\u043e\u0439 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0447\u0435\u0440\u0435\u0437 \u0441\u0438\u043c\u0432\u043e\u043b |:cat file.txt | grep &#171;error&#187; | sort | uniq\u0417\u0434\u0435\u0441\u044c \u043a\u0430\u0436\u0434\u0430\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u0435\u0442 \u043a\u0430\u043a Filter, \u0430 Pipe \u0441\u043b\u0443\u0436\u0438\u0442 \u043b\u0438\u0448\u044c \u043a\u0430\u043d\u0430\u043b\u043e\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u0435\u0436\u0434\u0443 \u044d\u0442\u0430\u043f\u0430\u043c\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438.\u0412 MassTransit \u043c\u043e\u0434\u0435\u043b\u044c \u0441\u043b\u043e\u0436\u043d\u0435\u0435. \u0425\u043e\u0442\u044f \u0442\u0435\u0440\u043c\u0438\u043d\u043e\u043b\u043e\u0433\u0438\u044f Pipes \u0438 Filters \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f, \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0431\u043b\u0438\u0436\u0435 \u043a Middleware Pipeline, \u0447\u0435\u043c \u043a \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u043e\u043c\u0443 Pipes &amp; Filters. \u0426\u0435\u043f\u043e\u0447\u043a\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043a\u0430\u043a \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c Pipe -&gt; Filter -&gt; Pipe -&gt; Filter, \u043e\u0434\u043d\u0430\u043a\u043e \u043a\u0430\u0436\u0434\u044b\u0439 Filter \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442 \u0435\u0433\u043e \u0434\u0430\u043b\u044c\u0448\u0435, \u0430 \u043c\u043e\u0436\u0435\u0442:\u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0438\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435\u043c \u0446\u0435\u043f\u043e\u0447\u043a\u0438\u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438\u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0432\u0435\u0442\u0432\u043b\u0435\u043d\u0438\u044f\u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435\u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 Pipes\u0422\u043e \u0435\u0441\u0442\u044c Filter \u0437\u0434\u0435\u0441\u044c \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u0435\u0442 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u043c, \u043d\u043e \u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u043c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0442\u043e\u043a\u043e\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f (Control Flow), \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443 MassTransit \u0431\u043b\u0438\u0436\u0435 \u043a middleware-\u043f\u043e\u0434\u0445\u043e\u0434\u0443, \u0433\u0434\u0435 \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u0443\u0435\u0442, \u043a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0448\u0430\u0433. \u0418\u043c\u0435\u043d\u043d\u043e \u043f\u043e\u044d\u0442\u043e\u043c\u0443 Pipeline \u0432 MassTransit &#8212; \u044d\u0442\u043e \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043b\u0438\u043d\u0435\u0439\u043d\u0430\u044f \u0446\u0435\u043f\u043e\u0447\u043a\u0430 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432, \u0430 \u0431\u043e\u043b\u0435\u0435 \u0433\u0438\u0431\u043a\u0430\u044f \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u0430\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439.\u041e\u0442\u0441\u044e\u0434\u0430 \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0437\u044e\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u043a\u0430\u043a Pipes &amp; Filter \u0441 Middleware Control FlowGreenPipes \u0441\u0442\u0440\u043e\u0438\u0442\u0441\u044f \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u0445Agents &#8212;  \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u043c \u0446\u0438\u043a\u043b\u043e\u043c \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0412 \u0447\u0430\u0441\u0442\u044c \u0438\u0445 \u043e\u0431\u044f\u0437\u0430\u043d\u043d\u043e\u0441\u0442\u0435\u0439 \u0432\u0445\u043e\u0434\u0438\u0442: \u0441\u0442\u0430\u0440\u0442, \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0433\u043e\u0442\u043e\u0432\u043d\u043e\u0441\u0442\u0438, \u0441\u0438\u0433\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0430\u0445 \u0412 \u043f\u0440\u0438\u043c\u0435\u0440 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 RabbitMqBasicConsumer, \u0447\u0442\u043e \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f Agent\u2019\u043e\u043c, \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043a\u0440\u0443\u0442\u0438\u0442\u0441\u044f \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u044b\u0439 loop \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u0417\u0434\u0435\u0441\u044c \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d \u043c\u0435\u0442\u043e\u0434 HandleBasicDeliver \u0438\u0437 rabbitmq.clientpublic class RabbitMqBasicConsumer :        Agent,        IAsyncBasicConsumer,        IBasicConsumer,        RabbitMqDeliveryMetrics    {        readonly RabbitMqReceiveEndpointContext _context;        readonly TaskCompletionSource&lt;bool&gt; _deliveryComplete;        readonly IReceivePipeDispatcher _dispatcher;        readonly SemaphoreSlim _limit;        readonly ModelContext _model;        readonly ConcurrentDictionary&lt;ulong, RabbitMqReceiveContext&gt; _pending;        readonly ReceiveSettings _receiveSettings;        string _consumerTag;        EventHandler&lt;ConsumerEventArgs&gt; _onConsumerCancelled;        \/\/\/ &lt;summary&gt;        \/\/\/ The basic consumer receives messages pushed from the broker.        \/\/\/ &lt;\/summary&gt;        \/\/\/ &lt;param name=&#187;model&#187;&gt;The model context for the consumer&lt;\/param&gt;        \/\/\/ &lt;param name=&#187;context&#187;&gt;The topology&lt;\/param&gt;        public RabbitMqBasicConsumer(ModelContext model, RabbitMqReceiveEndpointContext context)        {            _model = model;            _context = context;            _receiveSettings = model.GetPayload&lt;ReceiveSettings&gt;();            _pending = new ConcurrentDictionary&lt;ulong, RabbitMqReceiveContext&gt;();            _dispatcher = context.CreateReceivePipeDispatcher();            _dispatcher.ZeroActivity += HandleDeliveryComplete;            _deliveryComplete = TaskUtil.GetTask&lt;bool&gt;();            if (context.ConcurrentMessageLimit.HasValue)                _limit = new SemaphoreSlim(context.ConcurrentMessageLimit.Value);            ConsumerCancelled += OnConsumerCancelled;        }&#8230;        Task IAsyncBasicConsumer.HandleBasicDeliver(string consumerTag, ulong deliveryTag, bool redelivered, string exchange, string routingKey,            IBasicProperties properties, ReadOnlyMemory&lt;byte&gt; body)        {            HandleBasicDeliver(consumerTag, deliveryTag, redelivered, exchange, routingKey, properties, body);            return Task.CompletedTask;        }public void HandleBasicDeliver(string consumerTag, ulong deliveryTag, bool redelivered, string exchange, string routingKey,            IBasicProperties properties, ReadOnlyMemory&lt;byte&gt; body)        {            var bodyBytes = body.ToArray();            Task.Run(async () =&gt;            {                LogContext.Current = _context.LogContext;                var context = new RabbitMqReceiveContext(exchange, routingKey, _consumerTag, deliveryTag, bodyBytes, redelivered, properties,                    _context, _receiveSettings, _model, _model.ConnectionContext);                var added = _pending.TryAdd(deliveryTag, context);                if (!added &amp;&amp; deliveryTag != 1) \/\/ DIRECT REPLY-TO fixed value                    LogContext.Warning?.Log(&#171;Duplicate BasicDeliver: {DeliveryTag}&#187;, deliveryTag);                var receiveLock = _receiveSettings.NoAck ? default : new RabbitMqReceiveLockContext(_model, deliveryTag);                if (_limit != null)                    await _limit.WaitAsync(context.CancellationToken).ConfigureAwait(false);                try                {                    await _dispatcher.Dispatch(context,&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-479302","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/479302","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=479302"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/479302\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=479302"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=479302"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=479302"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}