Skip to content

Commit bb3b8aa

Browse files
committed
Join the original Aspire benchmark disposal task
Await the testing factory's original DisposeAsync task instead of its cancelable StopAsync wrapper. Capture the configured host shutdown budget before startup and retain the existing original-task settlement budget after it. Remove the manual container-stop path, which timed out InfluxDB after its workload had passed. Verified: complete Debug solution build with -warnaserror (0 warnings/errors), full format verification and repository governance. Real ClickHouse 1M and InfluxDB controls passed on unchanged source/DLL/PDB inputs; their owned containers and anonymous volumes were removed. Full Linux session qualification follows this checkpoint.
1 parent 7178457 commit bb3b8aa

7 files changed

Lines changed: 32 additions & 77 deletions

File tree

‎benchmarks/KeyLoad.ComparisonHost/DatabaseAdapters/Resources/AdditionalDatabaseResources.cs‎

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,12 @@ or BenchmarkAdditionalTargets.MySql or BenchmarkAdditionalTargets.ClickHouse or
5252
failures.Add(failure);
5353
}
5454
await SettleAsync(observations.CompleteAsync, failures);
55-
using var stop = new CancellationTokenSource(ExecutionPolicyFixture.Harness().Value.OriginalTaskSettlementTimeout, TimeProvider.System);
56-
await SettleAsync(() => IsolatedResourceShutdown.StopAsync(application, containers, stop.Token), failures);
5755
await SettleAsync(capture.StopAsync, failures);
5856
await SettleAsync(() => capture.WriteResourcesToAsync(root), failures);
5957
await SettleAsync(() => capture.DisposeAsync().AsTask(), failures);
60-
var beforeStop = failures.Count;
61-
await SettleAsync(() => application.StopAsync(CancellationToken.None), failures);
58+
var beforeDisposal = failures.Count;
6259
await SettleAsync(() => application.DisposeAsync().AsTask(), failures);
63-
if (failures.Count == beforeStop)
60+
if (failures.Count == beforeDisposal)
6461
{
6562
await SettleAsync(() => IsolatedDataCleanup.DeleteAsync(IsolatedResourceContext.ExecutionDirectory(root), containers), failures);
6663
}

‎benchmarks/KeyLoad.ComparisonHost/Orchestration/Fixtures/BenchmarkSessionAspireFixture.cs‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
using KeyLoad.LoadTests.AppHost.BenchmarkComparisons;
88
using Microsoft.Extensions.Configuration;
99
using Microsoft.Extensions.DependencyInjection;
10+
using Microsoft.Extensions.Hosting;
1011
using Microsoft.Extensions.Logging;
12+
using Microsoft.Extensions.Options;
1113

1214
namespace KeyLoad.ComparisonHost.BenchmarkOrchestration;
1315

@@ -56,7 +58,8 @@ private static async Task RunOwnedAsync(DistributedApplication application, Benc
5658
var containers = application.Services.GetRequiredService<DistributedApplicationModel>()
5759
.Resources.OfType<ContainerResource>().ToArray();
5860
var execution = ExecutionPolicyFixture.Harness();
59-
var work = new IsolatedOwnedWork(execution);
61+
var shutdown = application.Services.GetRequiredService<IOptions<HostOptions>>().Value.ShutdownTimeout;
62+
var work = new IsolatedOwnedWork(execution, shutdown);
6063
Exception? primary = null;
6164
try
6265
{

‎benchmarks/KeyLoad.ComparisonHost/Orchestration/Fixtures/IsolatedOwnedWork.cs‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,17 @@ internal ComparisonTestLogCapture? Capture
3939
private Task? runnerStop;
4040
private Task? disposing;
4141

42-
internal IsolatedOwnedWork(IOptions<ComparisonHarnessOptions> executionOptions)
42+
internal IsolatedOwnedWork(IOptions<ComparisonHarnessOptions> executionOptions, TimeSpan hostShutdownTimeout)
4343
{
4444
ArgumentNullException.ThrowIfNull(executionOptions);
45+
ArgumentOutOfRangeException.ThrowIfLessThan(hostShutdownTimeout, TimeSpan.Zero);
4546
executionOptions.Value.Validate();
4647
ExecutionOptions = executionOptions;
48+
HostShutdownTimeout = hostShutdownTimeout;
4749
}
4850

51+
internal TimeSpan HostShutdownTimeout { get; }
52+
4953
internal IOptions<ComparisonHarnessOptions> ExecutionOptions
5054
{
5155
get;

‎benchmarks/KeyLoad.ComparisonHost/Orchestration/Lifecycle/IsolatedOriginalTaskSettlement.cs‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@ namespace KeyLoad.ComparisonHost.BenchmarkOrchestration;
55
internal static class IsolatedOriginalTaskSettlement
66
{
77
internal static async Task<bool> RunAsync(Func<Task> start, string stage,
8-
IsolatedTeardownFailures failures, IOptions<ComparisonHarnessOptions> options, Func<Task>? escalate = null)
8+
IsolatedTeardownFailures failures, IOptions<ComparisonHarnessOptions> options, Func<Task>? escalate = null,
9+
TimeSpan shutdownAllowance = default)
910
{
11+
ArgumentOutOfRangeException.ThrowIfLessThan(shutdownAllowance, TimeSpan.Zero);
12+
var settlementTimeout = shutdownAllowance + options.Value.OriginalTaskSettlementTimeout;
1013
var initiation = StartAsync(start);
1114
Task original;
1215
try
@@ -18,7 +21,7 @@ internal static async Task<bool> RunAsync(Func<Task> start, string stage,
1821
Record(initiation, failure, stage, failures);
1922
return false;
2023
}
21-
return await JoinAsync(original, stage, failures, options, escalate);
24+
return await JoinAsync(original, stage, failures, options, escalate, settlementTimeout);
2225
}
2326

2427
private static async Task<Task> StartAsync(Func<Task> start)
@@ -28,9 +31,10 @@ private static async Task<Task> StartAsync(Func<Task> start)
2831
}
2932

3033
private static async Task<bool> JoinAsync(Task original, string stage,
31-
IsolatedTeardownFailures failures, IOptions<ComparisonHarnessOptions> options, Func<Task>? escalate)
34+
IsolatedTeardownFailures failures, IOptions<ComparisonHarnessOptions> options, Func<Task>? escalate,
35+
TimeSpan settlementTimeout)
3236
{
33-
var wait = original.WaitAsync(options.Value.OriginalTaskSettlementTimeout, TimeProvider.System);
37+
var wait = original.WaitAsync(settlementTimeout, TimeProvider.System);
3438
try
3539
{
3640
await wait;

‎benchmarks/KeyLoad.ComparisonHost/Orchestration/Lifecycle/IsolatedResourceShutdown.cs‎

Lines changed: 0 additions & 37 deletions
This file was deleted.

‎benchmarks/KeyLoad.ComparisonHost/Orchestration/Scenarios/IsolatedTeardown.cs‎

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ internal static class IsolatedTeardown
2121
private const int EmptyCount = 0;
2222
private const string ServerResourceValue = "server-resource";
2323
private const string ServerResourceTaskOwnershipWasIncompleteMessage = "Server resource task ownership was incomplete.";
24-
private const string StopStage = "stop";
25-
private const string ResourcesStopStage = "resources-stop";
2624
private const string SessionStateJsonFileName = "session-state.json";
2725
private const string SessionJsonFileName = "session.json";
2826
private const string SessionResourceEvidenceJsonFileName = "session-resource-evidence.json";
@@ -55,7 +53,6 @@ private static async Task CompleteCoreAsync(DistributedApplication app, Comparis
5553
var runnerSettled = await IsolatedOriginalTaskSettlement.RunAsync(
5654
work.StopRunnerAsync, ExecutionRunnerValue, failures, options);
5755
var collectorSettled = await SettleCollectorAsync(work, failures, options);
58-
var resourcesStopped = await StopResourcesAsync(app, containers, failures, options);
5956
var captureSettled = capture is null || await IsolatedOriginalTaskSettlement.RunAsync(
6057
capture.StopAsync, LogsCloseValue, failures, options);
6158
if (capture is not null)
@@ -66,15 +63,17 @@ await IsolatedOriginalTaskSettlement.RunAsync(
6663
() => capture.WriteResourcesToAsync(evidence), NodeLogsRetainValue, failures, options);
6764
}
6865
await IsolatedOriginalTaskSettlement.RunAsync(() => CopyRawAsync(output, evidence), RawReportStage, failures, options);
69-
var stopped = await StopAsync(app, failures, options);
7066
var captureDisposed = disposeCapture is null || await IsolatedOriginalTaskSettlement.RunAsync(
7167
disposeCapture, CaptureDisposeValue, failures, options);
68+
// Own the testing factory's original disposal task, including its configured host shutdown budget.
69+
// The testing application's cancelable StopAsync wait does not own that task's completion.
7270
var applicationDisposed = await IsolatedOriginalTaskSettlement.RunAsync(
73-
() => app.DisposeAsync().AsTask(), AppDisposeValue, failures, options);
74-
var reportsRetained = stopped && applicationDisposed
71+
() => app.DisposeAsync().AsTask(), AppDisposeValue, failures, options,
72+
shutdownAllowance: work.HostShutdownTimeout);
73+
var reportsRetained = applicationDisposed
7574
&& await IsolatedOriginalTaskSettlement.RunAsync(() => RetainReportsAsync(output, evidence),
7675
ExecutionTrxRetainValue, failures, options);
77-
if (runnerSettled && collectorSettled && resourcesStopped && captureSettled && captureDisposed && stopped && applicationDisposed && reportsRetained)
76+
if (runnerSettled && collectorSettled && captureSettled && captureDisposed && applicationDisposed && reportsRetained)
7877
{
7978
await IsolatedOriginalTaskSettlement.RunAsync(
8079
() => IsolatedDataCleanup.DeleteAsync(root, containers), DataStage, failures, options);
@@ -124,23 +123,6 @@ private static async Task<bool> SettleCollectorAsync(IsolatedOwnedWork work,
124123
return await IsolatedOriginalTaskSettlement.RunAsync(() => original, ServerResourceValue, failures, options);
125124
}
126125

127-
private static async Task<bool> StopAsync(DistributedApplication app,
128-
IsolatedTeardownFailures failures, IOptions<ComparisonHarnessOptions> options)
129-
{
130-
using var cancellation = new CancellationTokenSource();
131-
return await IsolatedOriginalTaskSettlement.RunAsync(
132-
() => app.StopAsync(cancellation.Token), StopStage, failures, options, cancellation.CancelAsync);
133-
}
134-
135-
private static async Task<bool> StopResourcesAsync(DistributedApplication app, ContainerResource[] containers,
136-
IsolatedTeardownFailures failures, IOptions<ComparisonHarnessOptions> options)
137-
{
138-
using var cancellation = new CancellationTokenSource();
139-
return await IsolatedOriginalTaskSettlement.RunAsync(
140-
() => IsolatedResourceShutdown.StopAsync(app, containers, cancellation.Token), ResourcesStopStage,
141-
failures, options, cancellation.CancelAsync);
142-
}
143-
144126
private static Task RetainReportsAsync(string output, string evidence)
145127
{
146128
WorkloadTestReports.Retain(output, evidence);

‎docs/Features/BenchmarkComparisons/SessionExecution.md‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,13 @@ the same joined lifecycle and validate anonymous-volume ownership before removin
196196
their host data directory. Original resource identities and logs remain available.
197197
Measured document deletes still use the real native mutation path.
198198

199-
After the workload and resource observers settle, the client requests each created
200-
container's registered Aspire stop command and awaits its actual exit notification.
201-
Resource logs remain open until these exits are observed. Application disposal
202-
then removes the stopped session containers and anonymous volumes. Each shutdown
203-
stage retains its 30-second deadline; a rejected command, missing exit, timeout or
199+
After the workload, resource observers and captured logs settle, the fixture owns
200+
and awaits the original Aspire testing application's `DisposeAsync` task. The
201+
testing factory owns host shutdown, session containers and anonymous volumes.
202+
Its configured `HostOptions.ShutdownTimeout` remains unchanged. The outer disposal
203+
join allows that host-shutdown budget plus the existing 30-second original-task
204+
settlement budget; other teardown stages retain their 30-second deadlines. The
205+
original disposal task remains joined after a threshold, and any timeout or
204206
disposal failure still fails the original session.
205207

206208
ClickHouse uses native patch-part `UPDATE` and `DELETE FROM` operations over the

0 commit comments

Comments
 (0)