Передача TraceId (CorrelationId) между сервисами ASP.NET Core
Полезности | создано: 11.04.2020 | опубликовано: 11.04.2020 | обновлено: 13.01.2024 | просмотров: 9331
Библиотека, которая призвана упростить передачу TraceId (CorrelationId) между микросервисами.
Что такое TraceId
В микросервисной архитектуре много сервисов по определению. Значит одна бизнес-операция может "пролегать" через несколько сервисов, а значит множество REST-запросов "полетят" по разным WebAPI. Например, оплата в интернет-магазине товара является бизнес-операцией, которая может состоять из нескольких запросов: оплата счета, отправка уведомлений, сбор статистики и т.д. И каждый из перечисленных запросов может (и должен) обрабатываться отдельным сервисом. Вопрос, как фильтровать все запросы для одной бизнес-операции чтобы отследить результаты? Ответ - надо чтобы все запросы были помечены одной и той же меткой (идентификатором). Такой идентификатор обычно называют CorrelationId (я называю TraceId, потому что так короче и писать проще).
Как это работает
Работает система на базе заголовков (headers) запросов. И в REST-запросах, и в MessageQueue-запросах... Почему используются "заголовки"? Перефразирую вопрос, почему нельзя сделать ViewModel, к котором будет TraceId? Тезисно:
- Потому что эта операция стоит над бизнес-логикой и, следовательно, не должна смешиваться.
- Потому что ваши ViewModels будут меняться, появляться, исчезать, а запросы изменяются очень и очень редко.
- Потому что обработка TraceId происходит в том числе и другими сервисами. Например, для сбора статистики или мониторинга. А ваши ViewModels никто "залезать" не будет.
Как реализовать в ASP.NET Core?
Уже готовых решений в интернете полным-полно. Я использую библиотеку Calabonga.Microservices.Tracker, которой решил поделиться совершенно недавно. Как это работает.
- Установливаете nuget-пакет
- Настраиваете пару параметров
- И вуаля!
Настройка в методе ConfigureServices
Настройка достаточно гибкая и имеет несколько варинатов.
Вариант 1: Самый простой
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { // Omitted for brevity ... services.AddCommunicationTracker(); ... }
Вариант 2: Установка своих параметров
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { // Omitted for brevity ... services.AddCommunicationTracker<DefaultTrackerIdGenerator>(options => { options.TrackerIdGenerator = () => "{ВАШ ГЕНЕРАТОР КОДА}"; options.EnforceHeader = false; options.IgnoreRequestHeader = false; options.RequestHeaderName = "X-Custom-Request-Trace-ID"; //Default is: X-Microservice-Trace-Id options.ResponseHeaderName = "X-Custom-Response-Trace-ID"; //Default is: X-Microservice-Trace-Id options.AddToLogger = true; options.LoggerScopeName = "MICROSERVICE_LOGGER"; options.IncludeInResponse = true; options.UpdateTraceIdentifier = true; }); ... }
Обратите внимание на класс DefaultTrackerIdGenerator. Это генератор идентификторов по типу Guid, который встроен в сборку Calabonga.Microservices.Tracker. Если вы хотети использовать свой собственный генератор, то его можно сделать например так:
public class CustomTrackerIdGenerator : ITrackerIdGenerator { /// <summary> /// Generates a tracker ID string for the current request. /// </summary> /// <param name="context">The <see cref="Microsoft.AspNetCore.Http.HttpContext"/> of the current request.</param> /// <returns>A string representing the tracker ID.</returns> public string GenerateTrackerId(HttpContext context) { return $"{TokenGenerator.Generate(11)}-{TokenGenerator.Generate(11)}"; } }
где TokenGenerator.Generate - это helper из сборки Calabonga.TokenGeneratorCore. И таким образом, можно этот генератор использовать так:
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { // Omitted for brevity ... services.AddCommunicationTracker<CustomTrackerIdGenerator>(); ... }
Как получить TraceId
Нужно внедрить зависимость `ITrackerContextAccessor ` и обратиться к контексту:
public class ProcessingEndpoints : AppDefinition
{
public override void ConfigureApplication(WebApplication app)
{
app.MapGet("/api/processions/start-validation/{processingId:guid}", StartValidation);
}
[ProducesResponseType(200)]
[ProducesResponseType(401)]
[Authorize(AuthenticationSchemes = AuthData.AuthSchemes)]
[FeatureGroupName("Processions")]
private async Task<IResult> StartValidation(Guid processingId, [FromServices] ITrackerContextAccessor trackerContext, [FromServices] IMediator mediator, HttpContext context)
{
var correlationId = trackerContext.TrackerContext.TrackerId;
var result = await mediator.Send(new ProcessingValidate.Request(processingId, Guid.Parse(correlationId)), context.RequestAborted);
return Results.Ok(result);
}
}
Правда, ничего сложного?
Настройка в методе Configure
Тут еще проще...
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) { ... app.UseCommunicationTracker(); ... }
Готово! Всё настроено для методов, но если вы захотите использовать HttpClient, то надо еще добавить его настройку в метод ConfigureServices:
services.AddHttpClient("MyClient").AddCommunicationTrackerForwarding();
Это скажет системе, чтобы она "прокидывала" TraceId в вызовы черезе HttpClient.
Заключение
Правда же ничего сложного? Будут вопросы - пишите! Почитаю...