Centralize Postgres connection string policy across all modules

Extract connection string building into PostgresConnectionStringPolicy so all
services use consistent pooling, application_name, and timeout settings.
Adopt the new policy in 20+ module DataSource/ServiceCollectionExtensions classes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
master
2026-04-06 08:51:04 +03:00
parent 517fa0a92d
commit ccdfd41e4f
64 changed files with 625 additions and 178 deletions

View File

@@ -20,7 +20,7 @@ namespace StellaOps.Scanner.Reachability.Cache;
/// </summary>
public sealed class PostgresReachabilityCache : IReachabilityCache
{
private readonly string _connectionString;
private readonly Services.PostgresReachabilityDataSourceProvider _dataSourceProvider;
private readonly ILogger<PostgresReachabilityCache> _logger;
private readonly TimeProvider _timeProvider;
@@ -28,8 +28,16 @@ public sealed class PostgresReachabilityCache : IReachabilityCache
string connectionString,
ILogger<PostgresReachabilityCache> logger,
TimeProvider? timeProvider = null)
: this(new Services.PostgresReachabilityDataSourceProvider(connectionString), logger, timeProvider)
{
_connectionString = connectionString ?? throw new ArgumentNullException(nameof(connectionString));
}
internal PostgresReachabilityCache(
Services.PostgresReachabilityDataSourceProvider dataSourceProvider,
ILogger<PostgresReachabilityCache> logger,
TimeProvider? timeProvider = null)
{
_dataSourceProvider = dataSourceProvider ?? throw new ArgumentNullException(nameof(dataSourceProvider));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_timeProvider = timeProvider ?? TimeProvider.System;
}
@@ -40,8 +48,7 @@ public sealed class PostgresReachabilityCache : IReachabilityCache
string graphHash,
CancellationToken cancellationToken = default)
{
await using var conn = new NpgsqlConnection(_connectionString);
await conn.OpenAsync(cancellationToken);
await using var conn = await OpenConnectionAsync(cancellationToken).ConfigureAwait(false);
// Get cache entry
const string entrySql = """
@@ -120,8 +127,7 @@ public sealed class PostgresReachabilityCache : IReachabilityCache
{
ArgumentNullException.ThrowIfNull(entry);
await using var conn = new NpgsqlConnection(_connectionString);
await conn.OpenAsync(cancellationToken);
await using var conn = await OpenConnectionAsync(cancellationToken).ConfigureAwait(false);
await using var tx = await conn.BeginTransactionAsync(cancellationToken);
try
@@ -202,8 +208,7 @@ public sealed class PostgresReachabilityCache : IReachabilityCache
string sinkMethodKey,
CancellationToken cancellationToken = default)
{
await using var conn = new NpgsqlConnection(_connectionString);
await conn.OpenAsync(cancellationToken);
await using var conn = await OpenConnectionAsync(cancellationToken).ConfigureAwait(false);
const string sql = """
SELECT p.is_reachable, p.path_length, p.confidence, p.computed_at
@@ -246,8 +251,7 @@ public sealed class PostgresReachabilityCache : IReachabilityCache
IEnumerable<string> affectedMethodKeys,
CancellationToken cancellationToken = default)
{
await using var conn = new NpgsqlConnection(_connectionString);
await conn.OpenAsync(cancellationToken);
await using var conn = await OpenConnectionAsync(cancellationToken).ConfigureAwait(false);
// For now, invalidate entire cache for service
// More granular invalidation would require additional indices
@@ -283,8 +287,7 @@ public sealed class PostgresReachabilityCache : IReachabilityCache
string serviceId,
CancellationToken cancellationToken = default)
{
await using var conn = new NpgsqlConnection(_connectionString);
await conn.OpenAsync(cancellationToken);
await using var conn = await OpenConnectionAsync(cancellationToken).ConfigureAwait(false);
const string sql = """
SELECT total_hits, total_misses, full_recomputes, incremental_computes,
@@ -392,4 +395,7 @@ public sealed class PostgresReachabilityCache : IReachabilityCache
await cmd.ExecuteNonQueryAsync(cancellationToken);
}
private ValueTask<NpgsqlConnection> OpenConnectionAsync(CancellationToken cancellationToken)
=> _dataSourceProvider.OpenConnectionAsync(cancellationToken);
}