Pr.BuildingBlocks.Cms.Http 1.1.0

dotnet add package Pr.BuildingBlocks.Cms.Http --version 1.1.0
                    
NuGet\Install-Package Pr.BuildingBlocks.Cms.Http -Version 1.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Pr.BuildingBlocks.Cms.Http" Version="1.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Pr.BuildingBlocks.Cms.Http" Version="1.1.0" />
                    
Directory.Packages.props
<PackageReference Include="Pr.BuildingBlocks.Cms.Http" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Pr.BuildingBlocks.Cms.Http --version 1.1.0
                    
#r "nuget: Pr.BuildingBlocks.Cms.Http, 1.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Pr.BuildingBlocks.Cms.Http@1.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Pr.BuildingBlocks.Cms.Http&version=1.1.0
                    
Install as a Cake Addin
#tool nuget:?package=Pr.BuildingBlocks.Cms.Http&version=1.1.0
                    
Install as a Cake Tool

Pr.BuildingBlocks.Cms.Http

Odporne klienty HTTP dla mikroserwisów CMS Polskiego Radia. Jeden helper rejestruje typowany HttpClient z pełnym pipeline'em odporności — timeout, retry i circuit breaker — opartym na Microsoft.Extensions.Http.Resilience (Polly v8).

Pakiet jest niezależny od Pr.BuildingBlocks.Cms.Infrastructure — ciągnie tylko jedną zależność (Microsoft.Extensions.Http.Resilience). Serwisy bez wychodzących wywołań HTTP nie muszą go referencjować.

  • Target framework: net8.0
  • PackageId: Pr.BuildingBlocks.Cms.Http
  • Wersja: 1.1.0

Spis treści


Instalacja

<PackageReference Include="Pr.BuildingBlocks.Cms.Http" Version="1.1.0" />

Pakiet ciągnie tranzytywnie Microsoft.Extensions.Http.Resilience (9.1.0) — usuń własny, bezpośredni PackageReference do tej paczki po migracji.


Quick start

W warstwie Infrastructure (np. ExternalServices/Extensions.cs):

using Pr.BuildingBlocks.Cms.Http;

internal static class Extensions
{
    public static IServiceCollection AddExternalServices(
        this IServiceCollection services, IConfiguration configuration)
    {
        var options = configuration.GetRequiredSection(ExternalClientsOptions.SectionName)
                          .Get<ExternalClientsOptions>()
                      ?? throw new InvalidOperationException(
                          $"Konfiguracja '{ExternalClientsOptions.SectionName}' jest wymagana.");

        services.AddResilientHttpClient<IExternalSearchClient, ExternalSearchClient>(options.SearchUrl);
        services.AddResilientHttpClient<IQueryServiceClient, QueryServiceClient>(options.QueryUrl);

        return services;
    }
}

Każdy klient dostaje własny, izolowany circuit breaker. Kolejność strategii w pipeline: rate limiter → total timeout → retry → circuit breaker → attempt timeout.


Konfiguracja per serwis

Drugi (opcjonalny) parametr nadpisuje domyślną politykę — np. związanie z appsettings.json:

services.AddResilientHttpClient<IImagesClient, ImagesClient>(opt.BaseUrl, resilience =>
{
    resilience.TotalRequestTimeoutSeconds = opt.TimeoutSeconds;
    resilience.MaxRetryAttempts = opt.RetryCount;
    resilience.CircuitBreaker.MinimumThroughput = 20;
});

Walidacja wzajemnych zależności (SamplingDuration >= 2 × AttemptTimeout, TotalTimeout > AttemptTimeout) odbywa się na etapie rejestracji — z czytelnym ArgumentException, zanim handler rzuciłby mniej zrozumiały błąd przy starcie aplikacji.


Domyślne wartości

Parametr Domyślnie Uwagi
TotalRequestTimeoutSeconds 30 Budżet na całość żądania wraz z retry
AttemptTimeoutSeconds 10 Limit pojedynczej próby
MaxRetryAttempts 3 Backoff wykładniczy + jitter (handler); musi być >= 1
RetryBaseDelaySeconds 2 Bazowe opóźnienie backoffu retry; 0 = retry natychmiastowy
DisableRetry false Wyłącza ponawianie (klient mutujący — patrz Retry a idempotentność)
CircuitBreaker.FailureRatio 0.5 Udział błędów otwierający obwód
CircuitBreaker.MinimumThroughput 10 Próg żądań w oknie (patrz niżej)
CircuitBreaker.SamplingDurationSeconds 30 Okno oceny FailureRatio
CircuitBreaker.BreakDurationSeconds 5 Czas otwartego obwodu (fail-fast)

HttpClient.Timeout jest ustawiany na Timeout.InfiniteTimeSpan — budżetem czasu zarządza strategia TotalRequestTimeout z pipeline'u, dzięki czemu retry nie są ucinane przedwcześnie przez timeout samego HttpClient.


Dlaczego MinimumThroughput = 10

Domyślny próg Microsoftu to 100 żądań w oknie 30 s, zanim breaker w ogóle może się otworzyć. Wewnętrzny CMS redakcyjny rzadko osiąga taki ruch na pojedynczą zależność, więc przy domyślnych progach circuit breaker bywa martwy — skonfigurowany, ale nigdy nie wyzwalany.

Obniżenie progu do 10 sprawia, że obwód jest realnie osiągalny przy ruchu redakcyjnym. Towarzyszące podniesienie FailureRatio do 0.5 chroni przed otwieraniem obwodu na pojedynczy przejściowy błąd (wymaga połowy nieudanych prób w oknie). Oba progi dostrój per serwis, jeśli masz realne metryki ruchu.


Retry a idempotentność

⚠️ Retry stosuje się do każdej metody HTTP — także POST. Standardowy handler ponawia przejściowe błędy (5xx, 408, błąd sieci) niezależnie od czasownika. Dla idempotentnych odczytów (GET — pobranie obrazu, autora, wyszukiwanie) to bezpieczne. Dla mutujących POST/PUT retry może podwoić efekt uboczny (np. double-create), jeśli pierwsze żądanie dotarło, a odpowiedź zginęła.

Dla klienta wykonującego niezabezpieczone operacje mutujące wyłącz retry:

services.AddResilientHttpClient<IPaymentsClient, PaymentsClient>(opt.BaseUrl, resilience =>
{
    resilience.DisableRetry = true; // brak retry — circuit breaker i timeouty nadal działają
});

Circuit breaker i limity czasu pozostają aktywne — wyłączasz wyłącznie ponawianie.


Obserwowalność

Zmiany stanu obwodu są logowane przez ILogger (kategoria Pr.BuildingBlocks.Cms.Http.CircuitBreaker), żeby otwarcie breakera w produkcji nie przeszło bez śladu:

  • OtwarcieLogWarning z nazwą klienta, czasem przerwy i przyczyną (kod HTTP / typ wyjątku).
  • Zamknięcie / half-openLogInformation.
warn: Pr.BuildingBlocks.Cms.Http.CircuitBreaker[0]
      Circuit breaker dla klienta IImagesClient OTWARTY na 5 s — downstream niedostępny (HTTP 503).

Niezależnie od tego standardowy handler emituje natywną telemetrię Polly (metryki + zdarzenia), którą można podłączyć pod OpenTelemetry / Grafanę. Warning powyżej to „głośny” sygnał do alertowania nawet bez wpiętego stacku metryk.


Migracja z lokalnego helpera

Serwisy, które miały skopiowany prywatny AddResilientHttpClient z AddStandardResilienceHandler:

  1. Dodaj PackageReference do Pr.BuildingBlocks.Cms.Http.
  2. Usuń bezpośredni PackageReference do Microsoft.Extensions.Http.Resilience (idzie tranzytywnie).
  3. Usuń lokalną prywatną metodę AddResilientHttpClient i using ...Http.Resilience.
  4. Dodaj using Pr.BuildingBlocks.Cms.Http; — sygnatura wywołań pozostaje identyczna.

Serwisy bez polityki odporności (gołe AddHttpClient) oraz pr.authors.cms (retry bez breakera) zyskują circuit breaker przez tę samą podmianę wywołania.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.1.0 104 6/1/2026
1.0.0 97 6/1/2026