From 296ee1a54470ceaa8193d754891edc92e52f0232 Mon Sep 17 00:00:00 2001 From: Flaminel Date: Wed, 14 Oct 2026 12:09:51 +0300 Subject: [PATCH] fixed stale http options after second settings update --- .../Http/DynamicHttpClientFactoryTests.cs | 24 ++++++++++++++++++- .../DynamicHttpClientFactory.cs | 2 ++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/code/backend/Cleanuparr.Infrastructure.Tests/Http/DynamicHttpClientFactoryTests.cs b/code/backend/Cleanuparr.Infrastructure.Tests/Http/DynamicHttpClientFactoryTests.cs index 2f50184f..0c35de5e 100644 --- a/code/backend/Cleanuparr.Infrastructure.Tests/Http/DynamicHttpClientFactoryTests.cs +++ b/code/backend/Cleanuparr.Infrastructure.Tests/Http/DynamicHttpClientFactoryTests.cs @@ -18,6 +18,7 @@ public sealed class DynamicHttpClientFactoryTests { private readonly IHttpClientConfigStore _store = new HttpClientConfigStore(); private readonly IHttpClientFactory _httpClientFactory = Substitute.For(); + private readonly OptionsCache _optionsCache = new(); private readonly DynamicHttpClientFactory _factory; public DynamicHttpClientFactoryTests() @@ -27,7 +28,7 @@ public sealed class DynamicHttpClientFactoryTests _factory = new DynamicHttpClientFactory( _httpClientFactory, _store, - new OptionsCache(), + _optionsCache, NullLogger.Instance); } @@ -162,6 +163,27 @@ public sealed class DynamicHttpClientFactoryTests requestedNames[0].ShouldNotBe(requestedNames[1]); } + [Fact] + public void UpdateAllClientsFromGeneralConfig_ShouldEvictTheBareName_OnEveryUpdate() + { + _factory.RegisterPlainClient("client", sendUserAgent: false); + GeneralConfig generalConfig = new() + { + HttpTimeout = 55, + HttpMaxRetries = 9, + HttpCertificateValidation = CertificateValidationType.Disabled, + HttpSendUserAgent = true, + }; + + // First update bumps the generation past 0, so the bare name stops matching GetGeneration's output. + _factory.UpdateAllClientsFromGeneralConfig(generalConfig); + + _optionsCache.TryAdd("client", new HttpClientFactoryOptions()); + _factory.UpdateAllClientsFromGeneralConfig(generalConfig); + + _optionsCache.TryRemove("client").ShouldBeFalse(); + } + private HttpClientConfig Stored(string clientName) { _store.TryGetConfiguration(clientName, out HttpClientConfig? config).ShouldBeTrue(); diff --git a/code/backend/Cleanuparr.Infrastructure/Http/DynamicHttpClientSystem/DynamicHttpClientFactory.cs b/code/backend/Cleanuparr.Infrastructure/Http/DynamicHttpClientSystem/DynamicHttpClientFactory.cs index 583ba9bc..d37e0efb 100644 --- a/code/backend/Cleanuparr.Infrastructure/Http/DynamicHttpClientSystem/DynamicHttpClientFactory.cs +++ b/code/backend/Cleanuparr.Infrastructure/Http/DynamicHttpClientSystem/DynamicHttpClientFactory.cs @@ -199,6 +199,8 @@ public class DynamicHttpClientFactory : IDynamicHttpClientFactory var clientNames = updatedConfigurations.Select(kvp => kvp.Key).ToList(); foreach (string clientName in clientNames) { + // Direct IHttpClientFactory consumers (ArrClient, notification proxies) request the bare name. + _optionsCache.TryRemove(clientName); _optionsCache.TryRemove(ComposeVersionedName(clientName, GetGeneration(clientName))); BumpGeneration(clientName); }