refactor(health.ef): review polish (timer release, timeout test, provider disposal, drop unused dep)
- Eagerly call CancelAfter(InfiniteTimeSpan) after a successful probe so the pending OS timer is released on the happy path rather than held for the full timeout window. - Add ProbeTimeout_Unhealthy test: 50 ms timeout with an infinite-blocking probe delegate asserts Unhealthy, covering the timeout code path. - Fix ProbeQueryThrows_Unhealthy to use Task.FromException rather than a synchronous throw, accurately modelling a faulted async delegate. - Wrap all BuildServiceProvider() results in await using so ServiceProvider is disposed after each test (no DI provider leak). - Remove unused Microsoft.EntityFrameworkCore.InMemory package reference; tests use SQLite only (InMemory CanConnect semantics differ and the package was not exercised). - Add <remarks> to DatabaseHealthCheck<TContext> noting the scoped-resolution path is safe for AddDbContextPool (scope dispose returns context to pool, not destroys it).
This commit is contained in:
@@ -24,6 +24,11 @@ namespace ZB.MOM.WW.Health.EntityFrameworkCore;
|
||||
/// disposed context); otherwise a scoped <typeparamref name="TContext"/> is resolved from a new DI
|
||||
/// scope. Recommended registration tag: <c>ZbHealthTags.Ready</c> (applied by the registrant).
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The scoped-resolution path is safe for <c>AddDbContextPool</c>: disposing the
|
||||
/// <see cref="IServiceScope"/> returns the pooled context to the pool rather than destroying it,
|
||||
/// so no pooled instance is prematurely discarded.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <typeparam name="TContext">The EF Core <see cref="DbContext"/> to probe.</typeparam>
|
||||
public sealed class DatabaseHealthCheck<TContext> : IHealthCheck
|
||||
@@ -59,7 +64,11 @@ public sealed class DatabaseHealthCheck<TContext> : IHealthCheck
|
||||
|
||||
try
|
||||
{
|
||||
return await ProbeAsync(timeoutCts.Token).ConfigureAwait(false);
|
||||
var result = await ProbeAsync(timeoutCts.Token).ConfigureAwait(false);
|
||||
// Eagerly release the pending timer on the happy path so the OS timer
|
||||
// resource is not held for the full timeout duration.
|
||||
timeoutCts.CancelAfter(Timeout.InfiniteTimeSpan);
|
||||
return result;
|
||||
}
|
||||
catch (OperationCanceledException ex)
|
||||
when (timeoutCts.IsCancellationRequested && !cancellationToken.IsCancellationRequested)
|
||||
|
||||
Reference in New Issue
Block a user