Почистить комментарии от упоминаний процесса
Удалены <remarks>, <summary> сжаты до короткой фразы, вырезаны ссылки на Task/Ruling/этап/python/прототип; //-комментарии со ссылками на процесс удалены; то же в .proto. Правила обновлены в docs/spec/Код-стайл-Дейл.md. Строк комментариев 27210 -> ~19100.
This commit is contained in:
@@ -9,19 +9,8 @@ using Deal.Grpc.Hosting.Services;
|
||||
namespace Deal.Grpc.Hosting.Interceptors;
|
||||
|
||||
/// <summary>
|
||||
/// Access-лог RPC Deal-сервисов (Ruling 7, план Task 14; общий шаблон трёх сервисов — C31): каждый
|
||||
/// вызов (кроме gRPC-health) — одна структурированная строка «метод → статус за N мс».
|
||||
/// Access-лог RPC Deal-сервисов
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Регистрируется ПЕРВЫМ в цепочке AddGrpc (до ServiceTokenInterceptor): логируются и отклонённые
|
||||
/// вызовы (401) — access-лог должен видеть отказы. Значения запросов не логируются (в RPC — тексты/
|
||||
/// промпты/ключи), секреты не пишутся (Ruling 13). gRPC-health (docker healthcheck ~5 с) пропускается —
|
||||
/// иначе лог был бы зашумлён инфраструктурными пробами.
|
||||
/// Access-лог ведётся для всех видов RPC (unary/клиентский/серверный/дуплексный стриминг): каждый
|
||||
/// handler-метод исполняется через общий <see cref="LogAsync"/>. «Прочие» сбои реализации (не
|
||||
/// отмена и не RpcException) логируются как Unknown и переводятся в RpcException — мимо лога они
|
||||
/// больше не уходят (замечание code-review).
|
||||
/// </remarks>
|
||||
public sealed class RpcCallLoggingInterceptor : Interceptor
|
||||
{
|
||||
// Префикс методов стандартного gRPC-health — не логируется (инфраструктурный liveness).
|
||||
@@ -35,7 +24,7 @@ public sealed class RpcCallLoggingInterceptor : Interceptor
|
||||
/// <summary>
|
||||
/// Создаёт интерцептор access-лога gRPC-вызовов.
|
||||
/// </summary>
|
||||
/// <param name="logger">Логгер (Serilog, Ruling 7).</param>
|
||||
/// <param name="logger">Логгер.</param>
|
||||
public RpcCallLoggingInterceptor(ILogger<RpcCallLoggingInterceptor> logger)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(logger);
|
||||
@@ -43,7 +32,7 @@ public sealed class RpcCallLoggingInterceptor : Interceptor
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Логирует unary-RPC: время вызова и итоговый gRPC-статус (успех либо статус исключения).
|
||||
/// Логирует unary-RPC
|
||||
/// </summary>
|
||||
public override Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
|
||||
TRequest request,
|
||||
@@ -52,7 +41,7 @@ public sealed class RpcCallLoggingInterceptor : Interceptor
|
||||
=> LogAsync(context, () => continuation(request, context));
|
||||
|
||||
/// <summary>
|
||||
/// Логирует client-streaming-RPC: access-строка пишется после завершения потока/вызова.
|
||||
/// Логирует client-streaming-RPC
|
||||
/// </summary>
|
||||
public override Task<TResponse> ClientStreamingServerHandler<TRequest, TResponse>(
|
||||
IAsyncStreamReader<TRequest> requestStream,
|
||||
@@ -61,7 +50,7 @@ public sealed class RpcCallLoggingInterceptor : Interceptor
|
||||
=> LogAsync(context, () => continuation(requestStream, context));
|
||||
|
||||
/// <summary>
|
||||
/// Логирует server-streaming-RPC: access-строка пишется после завершения потока/вызова.
|
||||
/// Логирует server-streaming-RPC
|
||||
/// </summary>
|
||||
public override Task ServerStreamingServerHandler<TRequest, TResponse>(
|
||||
TRequest request,
|
||||
@@ -71,7 +60,7 @@ public sealed class RpcCallLoggingInterceptor : Interceptor
|
||||
=> LogAsync(context, () => continuation(request, responseStream, context));
|
||||
|
||||
/// <summary>
|
||||
/// Логирует дуплексный RPC: access-строка пишется после завершения потока/вызова.
|
||||
/// Логирует дуплексный RPC
|
||||
/// </summary>
|
||||
public override Task DuplexStreamingServerHandler<TRequest, TResponse>(
|
||||
IAsyncStreamReader<TRequest> requestStream,
|
||||
|
||||
@@ -10,44 +10,26 @@ using Deal.Grpc.Hosting.Services;
|
||||
namespace Deal.Grpc.Hosting.Interceptors;
|
||||
|
||||
/// <summary>
|
||||
/// Серверный интерцептор service-token (Ruling 1; общий шаблон трёх Deal-сервисов — C31).
|
||||
///
|
||||
/// Каждый RPC Deal-сервиса обязан нести gRPC-metadata «service-token», равный ожидаемому значению
|
||||
/// из env DEAL_SERVICE_TOKEN (общий токен сервисов в compose, Ruling 12). Отсутствие или
|
||||
/// несовпадение токена — отказ UNAUTHENTICATED до вызова метода сервиса. Стандартный
|
||||
/// grpc.health.v1.Health токеном НЕ проверяется: это liveness инфраструктуры (docker healthcheck,
|
||||
/// Ruling 12), данных тенантов он не отдаёт.
|
||||
///
|
||||
/// Fail-closed (замечание ревью Task 2 учтено): если DEAL_SERVICE_TOKEN не задан/пуст — любой
|
||||
/// Deal-RPC отклоняется всегда. Явный гард обязателен: сравнение строк без него пропустило бы
|
||||
/// запрос с пустым значением metadata («» == «»), а env-провайдер конфигурации возвращает пустую
|
||||
/// строку вместо null для незаданного ключа.
|
||||
///
|
||||
/// Проверка выполняется для ВСЕХ видов RPC (unary/клиентский/серверный/дуплексный стриминг):
|
||||
/// метод <see cref="EnsureAuthorized"/> вызывается из каждого handler-а (замечание code-review).
|
||||
/// Серверный интерцептор service-token.
|
||||
/// </summary>
|
||||
public sealed class ServiceTokenInterceptor : Interceptor
|
||||
{
|
||||
/// <summary>
|
||||
/// Ключ gRPC-metadata с токеном сервиса (контракт — README src/contracts).
|
||||
/// Ключ gRPC-metadata с токеном сервиса
|
||||
/// </summary>
|
||||
public const string ServiceTokenMetadataKey = "service-token";
|
||||
|
||||
// Префикс методов стандартного gRPC-health, освобождённых от проверки токена.
|
||||
private const string HealthMethodPrefix = "/grpc.health.v1.Health/";
|
||||
|
||||
// Env-ключ ожидаемого токена (только env; ключи/секреты не логируются — Ruling 13).
|
||||
private const string ServiceTokenEnvKey = "DEAL_SERVICE_TOKEN";
|
||||
|
||||
// Деталь отказа — общий текст для трёх сервисов этапа (шаблон T2/T3/T4).
|
||||
private const string RejectionDetail = "service-token отсутствует или неверен";
|
||||
|
||||
private readonly byte[] _expectedTokenBytes;
|
||||
|
||||
/// <summary>
|
||||
/// Создаёт интерцептор. Ожидаемый токен читается из конфигурации (env DEAL_SERVICE_TOKEN)
|
||||
/// в момент старта хоста; смена токена требует рестарта (как остальной env-конфиг). Токен
|
||||
/// хранится в UTF-8-байтах для constant-time сравнения (<see cref="CryptographicOperations"/>).
|
||||
/// Создаёт интерцептор.
|
||||
/// </summary>
|
||||
/// <param name="configuration">Конфигурация хоста (env-провайдер WebApplicationBuilder).</param>
|
||||
public ServiceTokenInterceptor(IConfiguration configuration)
|
||||
|
||||
@@ -8,21 +8,8 @@ using Deal.Grpc.Hosting.Services;
|
||||
namespace Deal.Grpc.Hosting.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Загруженный набор сертификатов mTLS внутреннего gRPC (Ruling 6, план Task 13; общий шаблон — C31).
|
||||
/// Загруженный набор сертификатов mTLS внутреннего gRPC.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Создаётся один раз на старте процесса, когда <see cref="MtlsOptions.Enabled"/>=true, из файлов
|
||||
/// deploy/certs (генерация — scripts/mtls-certs.sh); при выключенном флаге <see cref="Load"/> возвращает
|
||||
/// null — процесс остаётся на plaintext + service-token (Ruling 2 этапа 6). Экземпляр живёт до конца
|
||||
/// процесса: сертификаты держат Kestrel (серверный) и исходящие каналы процессов с клиентской ролью
|
||||
/// (клиентский), поэтому IDisposable сознательно нет — преждевременный Dispose сломал бы живые
|
||||
/// соединения. Fail-fast: при включённом флаге любой пустой/битый путь или пароль —
|
||||
/// <see cref="InvalidOperationException"/> на старте.
|
||||
///
|
||||
/// Проверка второй стороны — цепочка на нашу CA (CustomRootTrust, без revocation): dev-CA не в системном
|
||||
/// хранилище, поэтому стандартная проверка доверия дала бы RemoteCertificateChainErrors и без кастомного
|
||||
/// билда цепочки каждое соединение отвергалось бы.
|
||||
/// </remarks>
|
||||
public sealed class MtlsCertificates
|
||||
{
|
||||
// Роль в сообщениях об ошибках: CA-сертификат (проверка второй стороны).
|
||||
@@ -45,23 +32,22 @@ public sealed class MtlsCertificates
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CA-сертификат из CaPem: корень доверия для проверки второй стороны.
|
||||
/// CA-сертификат из CaPem
|
||||
/// </summary>
|
||||
public X509Certificate2 CaCertificate { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Серверный сертификат процесса из PFX (подпись своего Kestrel-gRPC-эндпоинта).
|
||||
/// Серверный сертификат процесса из PFX
|
||||
/// </summary>
|
||||
public X509Certificate2 ServerCertificate { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Клиентский сертификат из PFX (подпись исходящих каналов, общий deal-client).
|
||||
/// Клиентский сертификат из PFX
|
||||
/// </summary>
|
||||
public X509Certificate2 ClientCertificate { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Загружает сертификаты из <paramref name="options"/>: null при выключенном флаге (режим plaintext),
|
||||
/// иначе — CA + серверный + клиентский с fail-fast на битые пути/пароли.
|
||||
/// Загружает сертификаты из <paramref name="options"/>
|
||||
/// </summary>
|
||||
/// <param name="options">Опции mTLS (env DEAL_MTLS_*).</param>
|
||||
/// <returns>Набор сертификатов либо null (флаг выключен).</returns>
|
||||
@@ -81,9 +67,7 @@ public sealed class MtlsCertificates
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Серверная проверка клиентского сертификата для Kestrel (ClientCertificateValidation): сертификат
|
||||
/// обязан быть подписан нашей CA (цепочка до CaPem). Стандартные ошибки цепочки (наша CA вне системного
|
||||
/// хранилища) пересобираются кастомным билдом; иные ошибки (нет сертификата/недоступен) — отказ.
|
||||
/// Серверная проверка клиентского сертификата для Kestrel
|
||||
/// </summary>
|
||||
/// <param name="certificate">Клиентский сертификат из рукопожатия (null — RequireCertificate не выполнен).</param>
|
||||
/// <param name="chain">Цепочка стандартной проверки (игнорируется — пересобирается на нашу CA).</param>
|
||||
@@ -112,8 +96,7 @@ public sealed class MtlsCertificates
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создаёт HTTP/2-хендлер исходящего канала: клиентский сертификат + проверка CA сервера
|
||||
/// (используют процессы с исходящими gRPC-каналами — общий шаблон).
|
||||
/// Создаёт HTTP/2-хендлер исходящего канала
|
||||
/// </summary>
|
||||
/// <returns>Новый SocketsHttpHandler (владелец — создатель; канал GrpcChannel закроет его вместе с собой).</returns>
|
||||
public SocketsHttpHandler CreateClientHttpHandler()
|
||||
|
||||
@@ -6,26 +6,17 @@ using Deal.Grpc.Hosting.Services;
|
||||
namespace Deal.Grpc.Hosting.Options;
|
||||
|
||||
/// <summary>
|
||||
/// Конфигурация mTLS-транспорта внутреннего gRPC (Ruling 6, план Task 13; общий шаблон — C31).
|
||||
/// Конфигурация mTLS-транспорта внутреннего gRPC.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Только env (Ruling 13: секреты/пути сертификатов не читаются из appsettings): флаг
|
||||
/// <c>DEAL_MTLS_ENABLED</c> и пути/пароли <c>DEAL_MTLS_*</c> из Ruling 6. Dev-дефолт — выключено
|
||||
/// (<see cref="Enabled"/> = false): процесс остаётся на plaintext + service-token (Ruling 2 этапа 6);
|
||||
/// PROD включает флаг env из compose-prod (Task 14; файлы монтируются из deploy/certs/, генерация —
|
||||
/// scripts/mtls-certs.sh). Env-схема общая для процессов Deal (Ruling 6): серверный PFX — для своего
|
||||
/// Kestrel-gRPC; клиентский PFX задаётся единообразно и используется процессами с исходящими
|
||||
/// каналами (общий deal-client); CA — для проверки второй стороны.
|
||||
/// </remarks>
|
||||
public sealed class MtlsOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Env-ключ флага: 1/true включает mTLS (как DEAL_DEMO=1).
|
||||
/// Env-ключ флага: 1/true включает mTLS
|
||||
/// </summary>
|
||||
public const string EnabledEnvKey = "DEAL_MTLS_ENABLED";
|
||||
|
||||
/// <summary>
|
||||
/// Env-ключ пути к PFX серверного сертификата процесса (Kestrel-gRPC).
|
||||
/// Env-ключ пути к PFX серверного сертификата процесса
|
||||
/// </summary>
|
||||
public const string ServerCertPfxEnvKey = "DEAL_MTLS_SERVER_CERT_PFX";
|
||||
|
||||
@@ -35,7 +26,7 @@ public sealed class MtlsOptions
|
||||
public const string ServerCertPasswordEnvKey = "DEAL_MTLS_SERVER_CERT_PASSWORD";
|
||||
|
||||
/// <summary>
|
||||
/// Env-ключ пути к PFX клиентского сертификата (общий deal-client исходящих каналов).
|
||||
/// Env-ключ пути к PFX клиентского сертификата
|
||||
/// </summary>
|
||||
public const string ClientCertPfxEnvKey = "DEAL_MTLS_CLIENT_CERT_PFX";
|
||||
|
||||
@@ -45,7 +36,7 @@ public sealed class MtlsOptions
|
||||
public const string ClientCertPasswordEnvKey = "DEAL_MTLS_CLIENT_CERT_PASSWORD";
|
||||
|
||||
/// <summary>
|
||||
/// Env-ключ пути к PEM dev-CA (проверка сертификата второй стороны).
|
||||
/// Env-ключ пути к PEM dev-CA
|
||||
/// </summary>
|
||||
public const string CaPemEnvKey = "DEAL_MTLS_CA_PEM";
|
||||
|
||||
@@ -55,32 +46,32 @@ public sealed class MtlsOptions
|
||||
public bool Enabled { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Путь к PFX серверного сертификата процесса (см. <see cref="ServerCertPfxEnvKey"/>).
|
||||
/// Путь к PFX серверного сертификата процесса
|
||||
/// </summary>
|
||||
public string ServerCertPfx { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Пароль серверного PFX (см. <see cref="ServerCertPasswordEnvKey"/>).
|
||||
/// Пароль серверного PFX
|
||||
/// </summary>
|
||||
public string ServerCertPassword { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Путь к PFX клиентского сертификата (см. <see cref="ClientCertPfxEnvKey"/>).
|
||||
/// Путь к PFX клиентского сертификата
|
||||
/// </summary>
|
||||
public string ClientCertPfx { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Пароль клиентского PFX (см. <see cref="ClientCertPasswordEnvKey"/>).
|
||||
/// Пароль клиентского PFX
|
||||
/// </summary>
|
||||
public string ClientCertPassword { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Путь к PEM-файлу dev-CA (см. <see cref="CaPemEnvKey"/>).
|
||||
/// Путь к PEM-файлу dev-CA
|
||||
/// </summary>
|
||||
public string CaPem { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Читает опции из конфигурации хоста (env-ключи DEAL_MTLS_*, только env — Ruling 13).
|
||||
/// Читает опции из конфигурации хоста.
|
||||
/// </summary>
|
||||
/// <param name="configuration">Конфигурация хоста (env-провайдер WebApplicationBuilder).</param>
|
||||
/// <returns>Опции mTLS (флаг выключен — остальные поля пустые).</returns>
|
||||
@@ -99,7 +90,7 @@ public sealed class MtlsOptions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Разбирает значение флага DEAL_MTLS_ENABLED: «1»/«true» (без учёта регистра) — включено.
|
||||
/// Разбирает значение флага DEAL_MTLS_ENABLED
|
||||
/// </summary>
|
||||
/// <param name="rawValue">Сырое значение env (null/пусто — выключено).</param>
|
||||
public static bool IsEnabled(string? rawValue)
|
||||
|
||||
@@ -11,23 +11,8 @@ using Deal.Grpc.Hosting.Options;
|
||||
namespace Deal.Grpc.Hosting.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Serilog-конфигурация процесса Deal-сервиса (Ruling 7/9, план Task 14; общий шаблон — C31).
|
||||
///
|
||||
/// Консоль — JSON в prod-стиле (CompactJsonFormatter: одна JSON-строка на событие, поля @t/@mt/@l —
|
||||
/// парсинг Loki/Promtail) либо текст в Development; плюс rolling-файл data/logs/deal-<процесс>.json
|
||||
/// под ContentRoot (/app в контейнере). Уровень/каталог переопределяются env: DEAL_LOG_LEVEL,
|
||||
/// DEAL_LOGS_DIR.
|
||||
/// Serilog-конфигурация процесса Deal-сервиса.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Конфигурация кодом, а не секцией appsettings: у сервиса appsettings.json нет (весь конфиг — env,
|
||||
/// Ruling 13), поэтому единый код-набор с env-переопределениями не расходится между процессами.
|
||||
/// Секреты не логируются (Ruling 13); OTel/метрики в этапе 7 не добавляются (Ruling 7) — стек:
|
||||
/// Serilog-логи → docker-логи → Promtail → Loki → Grafana.
|
||||
///
|
||||
/// Вызов — из Program.cs процесса (entry point): <c>DealLogging.Configure(builder, "имя_процесса")</c>
|
||||
/// ДО <c>builder.Build()</c>. Интеграционные тесты поднимают хост через *ServiceHost.Create БЕЗ этого
|
||||
/// вызова (логирование — забота production-точки входа), поэтому тесты не пишут файлы-логи.
|
||||
/// </remarks>
|
||||
public static class DealLogging
|
||||
{
|
||||
// Env-ключ минимального уровня Serilog (Debug/Information/Warning/Error; дефолт Information).
|
||||
@@ -56,8 +41,7 @@ public static class DealLogging
|
||||
private const LogEventLevel DefaultMinimumLevel = LogEventLevel.Information;
|
||||
|
||||
/// <summary>
|
||||
/// Подключает Serilog к хосту (builder.Host.UseSerilog). Регистрация отложенная: конфигурация
|
||||
/// логгера применяется при builder.Build(), когда среда/конфигурация (env) уже собраны.
|
||||
/// Подключает Serilog к хосту
|
||||
/// </summary>
|
||||
/// <param name="builder">Билдер WebApplication процесса (до Build).</param>
|
||||
/// <param name="processName">Имя процесса для имени файла-лога (telegram/ai/ml/…).</param>
|
||||
|
||||
@@ -10,33 +10,17 @@ using Deal.Grpc.Hosting.Options;
|
||||
namespace Deal.Grpc.Hosting.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Общая настройка метрик Deal-сервисов (этап 12, пакет A): OpenTelemetry → экспортёр Prometheus,
|
||||
/// эндпоинт <c>/metrics</c> в отдельном HTTP/1.1 Kestrel-эндпоинте (порт 9464 по умолчанию).
|
||||
/// Общая настройка метрик Deal-сервисов
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// gRPC-сервисы слушают HTTP/2 (см. <see cref="GrpcServer.ConfigureKestrelHttp2Endpoint"/>), а
|
||||
/// Prometheus scrape'ит обычным HTTP/1.1-запросом GET — поэтому метрики вынесены на отдельный
|
||||
/// Kestrel-эндпоинт с <see cref="HttpProtocols.Http1"/>: тот же процесс, тот же DI, но отдельный порт.
|
||||
/// Порт не публикуется наружу — scrape идёт внутри compose-сети от сервиса <c>prometheus</c>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Сервисы вызывают ровно две строки: <see cref="AddDealMetrics"/> — на этапе сборки хоста (до
|
||||
/// <c>builder.Build()</c>, обычно из <c>configureBuilder</c>-хука Program.cs), и
|
||||
/// <see cref="MapDealMetrics"/> — после сборки. Инструментация (входящие ASP.NET Core/gRPC,
|
||||
/// исходящие HTTP/gRPC) даёт метрики RPS/латентности/ошибок без ручного кода; прикладные метрики
|
||||
/// (токены, аудит, очереди) добавляет ядро своим meter'ом <see cref="MeterName"/>.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public static class DealMetricsHosting
|
||||
{
|
||||
/// <summary>
|
||||
/// Имя meter'а прикладных метрик Deal (общий префикс с ядром: <c>deal.*</c>).
|
||||
/// Имя meter'а прикладных метрик Deal
|
||||
/// </summary>
|
||||
public const string MeterName = "Deal";
|
||||
|
||||
/// <summary>
|
||||
/// Порт эндпоинта <c>/metrics</c> по умолчанию (конвенция OpenTelemetry Prometheus).
|
||||
/// Порт эндпоинта <c>/metrics</c> по умолчанию
|
||||
/// </summary>
|
||||
public const int DefaultMetricsPort = 9464;
|
||||
|
||||
@@ -44,9 +28,7 @@ public static class DealMetricsHosting
|
||||
private const string MetricsPortEnvKey = "METRICS_PORT";
|
||||
|
||||
/// <summary>
|
||||
/// Порт эндпоинта метрик: env <c>METRICS_PORT</c> (заданное нечисловое значение игнорируется),
|
||||
/// иначе <see cref="DefaultMetricsPort"/>. Локальный запуск нескольких процессов на хосте без
|
||||
/// compose требует разных значений (в compose порты контейнеров изолированы).
|
||||
/// Порт эндпоинта метрик
|
||||
/// </summary>
|
||||
/// <param name="defaultPort">Дефолтный порт (обычно <see cref="DefaultMetricsPort"/>).</param>
|
||||
/// <returns>Порт HTTP/1.1-эндпоинта метрик.</returns>
|
||||
@@ -56,8 +38,7 @@ public static class DealMetricsHosting
|
||||
: defaultPort;
|
||||
|
||||
/// <summary>
|
||||
/// Регистрирует OTel-метрики и Kestrel-эндпоинт метрик (HTTP/1.1, 0.0.0.0:<paramref name="metricsPort"/>).
|
||||
/// Вызывать до <c>builder.Build()</c>.
|
||||
/// Регистрирует OTel-метрики и Kestrel-эндпоинт метрик
|
||||
/// </summary>
|
||||
/// <param name="builder">Билдер хоста сервиса.</param>
|
||||
/// <param name="metricsPort">Порт HTTP/1.1-эндпоинта метрик.</param>
|
||||
@@ -86,7 +67,7 @@ public static class DealMetricsHosting
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Мапит эндпоинт <c>/metrics</c> (формат Prometheus). Вызывать после <c>builder.Build()</c>.
|
||||
/// Мапит эндпоинт <c>/metrics</c>
|
||||
/// </summary>
|
||||
/// <param name="app">Собранное приложение сервиса.</param>
|
||||
public static void MapDealMetrics(WebApplication app)
|
||||
|
||||
@@ -5,9 +5,7 @@ using Deal.Grpc.Hosting.Options;
|
||||
namespace Deal.Grpc.Hosting.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Общие стартовые проверки/разбор env для Program.cs Deal-сервисов (C31): порт Kestrel
|
||||
/// (GRPC_PORT → PORT → дефолт), окружение ASP.NET Core и fail-closed mTLS в Production
|
||||
/// (замечание code-review: отсутствие/опечатка DEAL_MTLS_ENABLED не должны давать «тихого» plaintext).
|
||||
/// Общие стартовые проверки/разбор env для Program.cs Deal-сервисов
|
||||
/// </summary>
|
||||
public static class GrpcHostEnvironment
|
||||
{
|
||||
@@ -28,8 +26,7 @@ public static class GrpcHostEnvironment
|
||||
"Production требует mTLS: задайте DEAL_MTLS_ENABLED=1 и env DEAL_MTLS_* (сертификаты deploy/certs, генерация — scripts/mtls-certs.sh)";
|
||||
|
||||
/// <summary>
|
||||
/// Порт Kestrel процесса: env GRPC_PORT (контейнер), затем PORT (общий env хостинг-платформ),
|
||||
/// иначе дефолт сервиса (Ruling 12, compose.dev.yml).
|
||||
/// Порт Kestrel процесса
|
||||
/// </summary>
|
||||
/// <param name="defaultPort">Дефолтный порт сервиса.</param>
|
||||
public static int ResolveGrpcPort(int defaultPort)
|
||||
@@ -38,15 +35,14 @@ public static class GrpcHostEnvironment
|
||||
?? defaultPort;
|
||||
|
||||
/// <summary>
|
||||
/// Парсит порт из env-строки; пустое/нечисловое значение — null (перебор следующего источника).
|
||||
/// Парсит порт из env-строки; пустое/нечисловое значение — null
|
||||
/// </summary>
|
||||
/// <param name="rawValue">Сырое значение env.</param>
|
||||
public static int? ParsePort(string? rawValue)
|
||||
=> int.TryParse(rawValue, out int parsedPort) ? parsedPort : null;
|
||||
|
||||
/// <summary>
|
||||
/// True — окружение Production (ASPNETCORE_ENVIRONMENT; незаданный env Production-ом не считается —
|
||||
/// dev-локальный запуск без переменной остаётся на plaintext, как раньше).
|
||||
/// True — окружение Production
|
||||
/// </summary>
|
||||
public static bool IsProductionEnvironment()
|
||||
=> string.Equals(
|
||||
@@ -55,9 +51,7 @@ public static class GrpcHostEnvironment
|
||||
StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Fail-closed-гард транспорта: при ASPNETCORE_ENVIRONMENT=Production и выключенном mTLS —
|
||||
/// отказ на старте с понятным текстом (Development и прочие не-prod окружения: plaintext
|
||||
/// + service-token допустимы, Ruling 2). Проверять после создания хоста (env уже собраны).
|
||||
/// Fail-closed-гард транспорта
|
||||
/// </summary>
|
||||
/// <param name="mtlsOptions">Опции mTLS процесса (из env DEAL_MTLS_*).</param>
|
||||
/// <exception cref="InvalidOperationException">Production без mTLS.</exception>
|
||||
|
||||
@@ -12,9 +12,7 @@ using Deal.Grpc.Hosting.Options;
|
||||
namespace Deal.Grpc.Hosting.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Общие серверные блоки gRPC-хостов Deal-сервисов (C31): mTLS-набор, Kestrel HTTP/2-эндпоинт,
|
||||
/// AddGrpc с интерцепторами и gRPC-health. Host-фабрики сервисов (TelegramServiceHost/AiServiceHost/
|
||||
/// MlServiceHost) собирают эти блоки здесь один раз, затем регистрируют свою доменную логику.
|
||||
/// Общие серверные блоки gRPC-хостов Deal-сервисов
|
||||
/// </summary>
|
||||
public static class GrpcServer
|
||||
{
|
||||
@@ -22,16 +20,12 @@ public static class GrpcServer
|
||||
private const string ReadyHealthCheckName = "ready";
|
||||
|
||||
/// <summary>
|
||||
/// Потолок входящего gRPC-сообщения (серверный лимит на границе, замечание code-review; 4 МБ —
|
||||
/// запросы контрактов сервисов помещаются с запасом).
|
||||
/// Потолок входящего gRPC-сообщения
|
||||
/// </summary>
|
||||
public const int DefaultMaxReceiveMessageSize = 4 * 1024 * 1024;
|
||||
|
||||
/// <summary>
|
||||
/// Загружает сертификаты mTLS из env (DEAL_MTLS_*, Ruling 6/Task 13) и регистрирует набор
|
||||
/// в DI: null при выключенном флаге (plaintext + service-token, dev); при включённом —
|
||||
/// fail-fast на битые пути/пароли. Возвращённый экземпляр используют Kestrel и (в процессах
|
||||
/// с клиентской ролью) исходящие каналы.
|
||||
/// Загружает сертификаты mTLS из env и регистрирует набор в DI
|
||||
/// </summary>
|
||||
/// <param name="builder">Билдер хоста (конфигурация env + DI).</param>
|
||||
/// <returns>Набор сертификатов либо null (mTLS выключен).</returns>
|
||||
@@ -50,9 +44,7 @@ public static class GrpcServer
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Настраивает единственный Kestrel-эндпоинт HTTP/2 на 0.0.0.0:grpcPort: plaintext (dev, Ruling 2)
|
||||
/// либо mTLS при переданном наборе сертификатов (серверный сертификат + требование клиентского
|
||||
/// с проверкой через нашу CA, Ruling 6).
|
||||
/// Настраивает единственный Kestrel-эндпоинт HTTP/2 на 0.0.0.0:grpcPort
|
||||
/// </summary>
|
||||
/// <param name="builder">Билдер хоста (WebHost для ConfigureKestrel).</param>
|
||||
/// <param name="grpcPort">TCP-порт Kestrel.</param>
|
||||
@@ -82,10 +74,7 @@ public static class GrpcServer
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Регистрирует AddGrpc с общей серверной обвязкой: access-лог ПЕРВЫМ (логирует и отклонённые
|
||||
/// вызовы), затем проверка service-token (Ruling 1) на каждом Deal-RPC; grpc.health.v1.Health
|
||||
/// освобождён от токена и access-лога (см. ServiceTokenInterceptor/RpcCallLoggingInterceptor).
|
||||
/// Плюс потолок входящего сообщения <see cref="DefaultMaxReceiveMessageSize"/>.
|
||||
/// Регистрирует AddGrpc с общей серверной обвязкой
|
||||
/// </summary>
|
||||
/// <param name="services">DI сервисов хоста.</param>
|
||||
public static IServiceCollection AddDealGrpcServer(this IServiceCollection services)
|
||||
@@ -101,8 +90,7 @@ public static class GrpcServer
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Регистрирует стандартный gRPC-health (Grpc.HealthCheck): healthcheck контейнера (Ruling 12)
|
||||
/// с явной проверкой <c>ready</c> — без неё health-сервис отвечает UNKNOWN, а не SERVING.
|
||||
/// Регистрирует стандартный gRPC-health
|
||||
/// </summary>
|
||||
/// <param name="services">DI сервисов хоста.</param>
|
||||
/// <param name="readyDetail">Текст готовности проверки (имя хоста в логах healthcheck).</param>
|
||||
|
||||
Reference in New Issue
Block a user