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:
@@ -38,7 +38,12 @@ public sealed class EvidenceLockerDataSource : IAsyncDisposable
|
||||
|
||||
private static NpgsqlDataSource CreateDataSource(string connectionString)
|
||||
{
|
||||
var builder = new NpgsqlDataSourceBuilder(connectionString);
|
||||
var connectionStringBuilder = new NpgsqlConnectionStringBuilder(connectionString)
|
||||
{
|
||||
ApplicationName = "stellaops-evidence-locker",
|
||||
};
|
||||
|
||||
var builder = new NpgsqlDataSourceBuilder(connectionStringBuilder.ConnectionString);
|
||||
builder.EnableDynamicJson();
|
||||
return builder.Build();
|
||||
}
|
||||
|
||||
@@ -83,10 +83,10 @@ public static class EvidenceLockerInfrastructureServiceCollectionExtensions
|
||||
// Verdict attestation repository
|
||||
services.AddScoped<StellaOps.EvidenceLocker.Storage.IVerdictRepository>(provider =>
|
||||
{
|
||||
var options = provider.GetRequiredService<IOptions<EvidenceLockerOptions>>().Value;
|
||||
var dataSource = provider.GetRequiredService<EvidenceLockerDataSource>();
|
||||
var logger = provider.GetRequiredService<ILogger<StellaOps.EvidenceLocker.Storage.PostgresVerdictRepository>>();
|
||||
return new StellaOps.EvidenceLocker.Storage.PostgresVerdictRepository(
|
||||
options.Database.ConnectionString,
|
||||
cancellationToken => dataSource.OpenConnectionAsync(cancellationToken),
|
||||
logger);
|
||||
});
|
||||
|
||||
@@ -94,10 +94,10 @@ public static class EvidenceLockerInfrastructureServiceCollectionExtensions
|
||||
// Sprint: SPRINT_20260219_009 (CID-04)
|
||||
services.AddScoped<StellaOps.EvidenceLocker.Storage.IEvidenceThreadRepository>(provider =>
|
||||
{
|
||||
var options = provider.GetRequiredService<IOptions<EvidenceLockerOptions>>().Value;
|
||||
var dataSource = provider.GetRequiredService<EvidenceLockerDataSource>();
|
||||
var logger = provider.GetRequiredService<ILogger<StellaOps.EvidenceLocker.Storage.PostgresEvidenceThreadRepository>>();
|
||||
return new StellaOps.EvidenceLocker.Storage.PostgresEvidenceThreadRepository(
|
||||
options.Database.ConnectionString,
|
||||
cancellationToken => dataSource.OpenConnectionAsync(cancellationToken),
|
||||
logger);
|
||||
});
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ Source of truth: `docs-archived/implplan/2025-12-29-csproj-audit/SPRINT_20251229
|
||||
|
||||
| Task ID | Status | Notes |
|
||||
| --- | --- | --- |
|
||||
| SPRINT_20260405_011-XPORT | DONE | `docs/implplan/SPRINT_20260405_011___Libraries_transport_pooling_and_attribution_hardening.md`: named the Evidence Locker PostgreSQL datasource and switched runtime repositories onto the shared open-connection path. |
|
||||
| AUDIT-0289-M | DONE | Revalidated 2026-01-07; open findings tracked in audit report. |
|
||||
| AUDIT-0289-T | DONE | Revalidated 2026-01-07; open findings tracked in audit report. |
|
||||
| AUDIT-0289-A | TODO | Revalidated 2026-01-07 (open findings). |
|
||||
|
||||
@@ -11,14 +11,14 @@ namespace StellaOps.EvidenceLocker.Storage;
|
||||
/// </summary>
|
||||
public sealed class PostgresEvidenceThreadRepository : IEvidenceThreadRepository
|
||||
{
|
||||
private readonly string _connectionString;
|
||||
private readonly Func<CancellationToken, Task<NpgsqlConnection>> _openConnectionAsync;
|
||||
private readonly ILogger<PostgresEvidenceThreadRepository> _logger;
|
||||
|
||||
public PostgresEvidenceThreadRepository(
|
||||
string connectionString,
|
||||
Func<CancellationToken, Task<NpgsqlConnection>> openConnectionAsync,
|
||||
ILogger<PostgresEvidenceThreadRepository> logger)
|
||||
{
|
||||
_connectionString = connectionString ?? throw new ArgumentNullException(nameof(connectionString));
|
||||
_openConnectionAsync = openConnectionAsync ?? throw new ArgumentNullException(nameof(openConnectionAsync));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
@@ -45,8 +45,7 @@ public sealed class PostgresEvidenceThreadRepository : IEvidenceThreadRepository
|
||||
|
||||
try
|
||||
{
|
||||
await using var connection = new NpgsqlConnection(_connectionString);
|
||||
await connection.OpenAsync(cancellationToken);
|
||||
await using var connection = await _openConnectionAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var record = await connection.QuerySingleOrDefaultAsync<ArtifactCanonicalRecord>(
|
||||
new CommandDefinition(
|
||||
@@ -88,8 +87,7 @@ public sealed class PostgresEvidenceThreadRepository : IEvidenceThreadRepository
|
||||
|
||||
try
|
||||
{
|
||||
await using var connection = new NpgsqlConnection(_connectionString);
|
||||
await connection.OpenAsync(cancellationToken);
|
||||
await using var connection = await _openConnectionAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var results = await connection.QueryAsync<ArtifactCanonicalRecord>(
|
||||
new CommandDefinition(
|
||||
|
||||
@@ -9,16 +9,16 @@ namespace StellaOps.EvidenceLocker.Storage;
|
||||
/// </summary>
|
||||
public sealed class PostgresVerdictRepository : IVerdictRepository
|
||||
{
|
||||
private readonly string _connectionString;
|
||||
private readonly Func<CancellationToken, Task<NpgsqlConnection>> _openConnectionAsync;
|
||||
private readonly ILogger<PostgresVerdictRepository> _logger;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
public PostgresVerdictRepository(
|
||||
string connectionString,
|
||||
Func<CancellationToken, Task<NpgsqlConnection>> openConnectionAsync,
|
||||
ILogger<PostgresVerdictRepository> logger,
|
||||
TimeProvider? timeProvider = null)
|
||||
{
|
||||
_connectionString = connectionString ?? throw new ArgumentNullException(nameof(connectionString));
|
||||
_openConnectionAsync = openConnectionAsync ?? throw new ArgumentNullException(nameof(openConnectionAsync));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
}
|
||||
@@ -74,8 +74,7 @@ public sealed class PostgresVerdictRepository : IVerdictRepository
|
||||
|
||||
try
|
||||
{
|
||||
await using var connection = new NpgsqlConnection(_connectionString);
|
||||
await connection.OpenAsync(cancellationToken);
|
||||
await using var connection = await _openConnectionAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var now = _timeProvider.GetUtcNow();
|
||||
var verdictId = await connection.ExecuteScalarAsync<string>(
|
||||
@@ -153,8 +152,7 @@ public sealed class PostgresVerdictRepository : IVerdictRepository
|
||||
|
||||
try
|
||||
{
|
||||
await using var connection = new NpgsqlConnection(_connectionString);
|
||||
await connection.OpenAsync(cancellationToken);
|
||||
await using var connection = await _openConnectionAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var record = await connection.QuerySingleOrDefaultAsync<VerdictAttestationRecord>(
|
||||
new CommandDefinition(
|
||||
@@ -231,8 +229,7 @@ public sealed class PostgresVerdictRepository : IVerdictRepository
|
||||
|
||||
try
|
||||
{
|
||||
await using var connection = new NpgsqlConnection(_connectionString);
|
||||
await connection.OpenAsync(cancellationToken);
|
||||
await using var connection = await _openConnectionAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var results = await connection.QueryAsync<VerdictAttestationSummary>(
|
||||
new CommandDefinition(
|
||||
@@ -309,8 +306,7 @@ public sealed class PostgresVerdictRepository : IVerdictRepository
|
||||
|
||||
try
|
||||
{
|
||||
await using var connection = new NpgsqlConnection(_connectionString);
|
||||
await connection.OpenAsync(cancellationToken);
|
||||
await using var connection = await _openConnectionAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var results = await connection.QueryAsync<VerdictAttestationSummary>(
|
||||
new CommandDefinition(
|
||||
@@ -365,8 +361,7 @@ public sealed class PostgresVerdictRepository : IVerdictRepository
|
||||
|
||||
try
|
||||
{
|
||||
await using var connection = new NpgsqlConnection(_connectionString);
|
||||
await connection.OpenAsync(cancellationToken);
|
||||
await using var connection = await _openConnectionAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var count = await connection.ExecuteScalarAsync<int>(
|
||||
new CommandDefinition(
|
||||
|
||||
Reference in New Issue
Block a user