fixed stale http auth after client update

This commit is contained in:
Flaminel committed 2026-10-15 19:06:26 +03:00
1 parent 49cc46a6d9
commit 1b0762abeb
4 files changed
+120 -11

No files matched your search

@@ -1,3 +1,4 @@
using System.Collections.Concurrent;
using System.Net;
using Cleanuparr.Domain.Enums;
using Cleanuparr.Persistence.Models.Configuration.General;
@@ -12,10 +13,13 @@ namespace Cleanuparr.Infrastructure.Http.DynamicHttpClientSystem;
/// </summary>
public class DynamicHttpClientFactory : IDynamicHttpClientFactory
{
private const char VersionSeparator = '#';
private readonly IHttpClientFactory _httpClientFactory;
private readonly IHttpClientConfigStore _configStore;
private readonly IOptionsMonitorCache<HttpClientFactoryOptions> _optionsCache;
private readonly ILogger<DynamicHttpClientFactory> _logger;
private readonly ConcurrentDictionary<string, int> _generations = new();
public DynamicHttpClientFactory(
IHttpClientFactory httpClientFactory,
@@ -29,10 +33,29 @@ public class DynamicHttpClientFactory : IDynamicHttpClientFactory
_logger = logger;
}
/// <summary>
/// Appends the generation so IHttpClientFactory builds a fresh handler. Generation 0 keeps the plain name.
/// </summary>
internal static string ComposeVersionedName(string clientName, int generation) =>
generation == 0 ? clientName : $"{clientName}{VersionSeparator}{generation}";
/// <summary>
/// Recovers the configuration store key from a name built by <see cref="ComposeVersionedName"/>.
/// </summary>
internal static string StripVersion(string versionedName)
{
int index = versionedName.IndexOf(VersionSeparator);
return index < 0 ? versionedName : versionedName[..index];
}
private int GetGeneration(string clientName) => _generations.GetOrAdd(clientName, 0);
private void BumpGeneration(string clientName) => _generations.AddOrUpdate(clientName, 1, (_, generation) => generation + 1);
public HttpClient CreateClient(string clientName, HttpClientConfig config)
{
_configStore.AddConfiguration(clientName, config);
return _httpClientFactory.CreateClient(clientName);
RegisterConfiguration(clientName, config);
return CreateClient(clientName);
}
public HttpClient CreateClient(string clientName)
@@ -41,12 +64,13 @@ public class DynamicHttpClientFactory : IDynamicHttpClientFactory
{
throw new InvalidOperationException($"No configuration found for client '{clientName}'. Register configuration first.");
}
return _httpClientFactory.CreateClient(clientName);
return _httpClientFactory.CreateClient(ComposeVersionedName(clientName, GetGeneration(clientName)));
}
public void RegisterConfiguration(string clientName, HttpClientConfig config)
{
// No bump: this runs on every download-service build, not only on changes.
_configStore.AddConfiguration(clientName, config);
}
@@ -132,8 +156,9 @@ public class DynamicHttpClientFactory : IDynamicHttpClientFactory
{
_configStore.RemoveConfiguration(clientName);
// Also invalidate the cached options for this client
_optionsCache.TryRemove(clientName);
// The cached handler outlives the options, so only a new name drops stale credentials.
_optionsCache.TryRemove(ComposeVersionedName(clientName, GetGeneration(clientName)));
BumpGeneration(clientName);
_logger.LogDebug("Unregistered and invalidated HTTP client configuration: {ClientName}", clientName);
}
@@ -174,7 +199,8 @@ public class DynamicHttpClientFactory : IDynamicHttpClientFactory
var clientNames = updatedConfigurations.Select(kvp => kvp.Key).ToList();
foreach (string clientName in clientNames)
{
_optionsCache.TryRemove(clientName);
_optionsCache.TryRemove(ComposeVersionedName(clientName, GetGeneration(clientName)));
BumpGeneration(clientName);
}
_logger.LogInformation("Updated and invalidated {Count} HTTP client configurations with new general settings: " +