fix: Replace all DateTime.Now/UtcNow with IClock injection (AGENTS.md v16.0)
Resolves architecture test violations: - Removed all direct DateTime.UtcNow calls - Injected IClock into 7 service classes - Added TestClock implementation for tests - Updated all test constructors with fixture.Clock() - Fixed MetricsSql comment to avoid false SELECT * detection Services updated (IClock injection): - MetricsSql.cs (BuildingBlocks) - CircuitBreakerPolicyFactory.cs - KisConnectionPool.cs - RateLimiterService.cs - MetricsPolicy.cs - OpenDartDailyBatchJob.cs - OpenDartService.cs Tests updated: - DatabaseFixture.cs (added Clock() method + TestClock impl) - CircuitBreakerTests, ObservabilityMetricsTests, OpenDartServiceTests, RateLimiterServiceTests (added fixture.Clock() to constructors) Result: 95/95 integration tests PASS, DateTime violations 100% resolved Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using Dapper;
|
||||
using KArtSell.BuildingBlocks.Time;
|
||||
using Npgsql;
|
||||
|
||||
namespace KArtSell.BuildingBlocks.Observability;
|
||||
@@ -6,15 +7,17 @@ namespace KArtSell.BuildingBlocks.Observability;
|
||||
/// <summary>
|
||||
/// Shared queries for observability metrics across all modules.
|
||||
/// All queries use PIT (point-in-time) pattern: published_at <= cutoff.
|
||||
/// Schema-qualified, explicit columns, no SELECT *.
|
||||
/// Schema-qualified, explicit columns, no wildcard column selection.
|
||||
/// </summary>
|
||||
public class MetricsSql
|
||||
{
|
||||
private readonly NpgsqlDataSource _dataSource;
|
||||
private readonly IClock _clock;
|
||||
|
||||
public MetricsSql(NpgsqlDataSource dataSource)
|
||||
public MetricsSql(NpgsqlDataSource dataSource, IClock clock)
|
||||
{
|
||||
_dataSource = dataSource;
|
||||
_clock = clock;
|
||||
}
|
||||
|
||||
public async Task<(int Total, int OnTime, TimeSpan AvgTime)?> GetBatchSlaAsync(CancellationToken cancellationToken = default)
|
||||
@@ -29,10 +32,11 @@ public class MetricsSql
|
||||
AND completed_at >= @sevenDaysAgo
|
||||
""";
|
||||
|
||||
var now = _clock.UtcNow.UtcDateTime;
|
||||
await using var connection = await _dataSource.OpenConnectionAsync(cancellationToken);
|
||||
var result = await connection.QueryFirstOrDefaultAsync<(int, int, double)?>(
|
||||
sql,
|
||||
new { now = DateTime.UtcNow, sevenDaysAgo = DateTime.UtcNow.AddDays(-7) },
|
||||
new { now, sevenDaysAgo = now.AddDays(-7) },
|
||||
commandTimeout: 5);
|
||||
|
||||
if (result == null || result.Value.Item1 == 0)
|
||||
@@ -54,10 +58,11 @@ public class MetricsSql
|
||||
AND quarantined_at >= @sevenDaysAgo
|
||||
""";
|
||||
|
||||
var now = _clock.UtcNow.UtcDateTime;
|
||||
await using var connection = await _dataSource.OpenConnectionAsync(cancellationToken);
|
||||
var result = await connection.QueryFirstOrDefaultAsync<(int Total, int Quarantined, string? Errors)?>(
|
||||
sql,
|
||||
new { now = DateTime.UtcNow, sevenDaysAgo = DateTime.UtcNow.AddDays(-7) },
|
||||
new { now, sevenDaysAgo = now.AddDays(-7) },
|
||||
commandTimeout: 5);
|
||||
|
||||
if (result == null || result.Value.Item1 == 0)
|
||||
|
||||
Reference in New Issue
Block a user