Repository navigation
Add Nitro seed update monitoring to Fusion Aspire - #10175
Conversation
There was a problem hiding this comment.
Pull request overview
Adds Nitro stage “seed update” monitoring to Fusion Aspire so AppHost runs can subscribe/query stage changes, download refreshed Fusion archives, and either auto-adopt them (triggering recomposition) or stage them for later. This extends the existing Nitro integration beyond startup-time seed acquisition and schema validation.
Changes:
- Introduces stage update subscription/query plumbing (GraphQL operations + client) and a background monitor/service that downloads and adopts or stages refreshed seeds.
- Adds Aspire resource commands to enable/disable Nitro auto-update, and wires seed adoption into recomposition flows (including manual recomposition fetching a fresh seed).
- Expands test coverage across monitoring behavior, race handling, and command registration/state.
Reviewed changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/HotChocolate/Fusion/test/Fusion.Aspire.Tests/NitroExtensionsTests.cs | Adds tests for seed update options and auto-update command registration/state. |
| src/HotChocolate/Fusion/test/Fusion.Aspire.Tests/Nitro/NitroStageUpdateClientTests.cs | Adds tests for stage update subscription/query ordering and header propagation. |
| src/HotChocolate/Fusion/test/Fusion.Aspire.Tests/Nitro/NitroSeedUpdateMonitorTests.cs | Adds comprehensive tests for the stage-change monitor behavior (adoption, staging, retries, backoff). |
| src/HotChocolate/Fusion/test/Fusion.Aspire.Tests/Nitro/NitroSchemaCompositionTests.cs | Verifies recomposition paths adopt fresh/staged seeds correctly and handles download failure fallback. |
| src/HotChocolate/Fusion/test/Fusion.Aspire.Tests/Nitro/NitroOperationDocumentsTests.cs | Validates new stage-update operation documents/IDs match embedded resources. |
| src/HotChocolate/Fusion/test/Fusion.Aspire.Tests/CompositionHarness.cs | Updates test harness wiring to include the new seed update service while disabling monitoring by default for tests. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/SchemaCompositionRegistration.cs | Registers seed update notifier/service and TimeProvider in DI. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/SchemaComposition.cs | Starts seed monitoring on gateway start; integrates staged/manual adoption into recomposition flows with rollback/reporting. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/NitroExtensions.cs | Adds AddNitro overload for seed update configuration and adds enable/disable auto-update commands to gateways. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/Operations/WatchNitroStage.graphql.sha256 | Adds persisted-operation hash sidecar for the stage watch subscription. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/Operations/WatchNitroStage.graphql | Adds subscription document for stage-change events (fusion config + client events). |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/Operations/GetNitroStageVersion.graphql.sha256 | Adds persisted-operation hash sidecar for querying the latest stage version. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/Operations/GetNitroStageVersion.graphql | Adds query document for current fusion configuration/client version state. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroStageUpdateClient.cs | Implements subscription + snapshot querying for stage changes via GraphQL over SSE. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroStageSnapshot.cs | Adds snapshot/change model + deterministic identity hashing for version deduplication. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroSeedUpdateState.cs | Adds candidate/snapshot/adoption state records used by coordinator/monitor. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroSeedUpdateService.cs | Adds per-gateway monitor lifecycle, command handling, and notification deduping/reporting. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroSeedUpdateOptions.cs | Adds public options controlling detection and auto-update behavior. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroSeedUpdateNotifier.cs | Adds Aspire interaction-based notifications for staged/adopted updates. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroSeedUpdateMonitor.cs | Implements background subscription/query loop, reconnect/backoff, download+adopt/stage logic. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroSeedCoordinator.cs | Extends coordinator to track staged/adopted state, schema hashing, and stage update client integration. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroOperationDocuments.cs | Adds stage update operation documents/IDs to embedded resource resolver. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroGatewaySeed.cs | Adds schema hash to the seed record for dedupe/adoption decisions. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroCompositionOptions.cs | Adds SeedUpdates options bag to composition options. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/INitroStageUpdateClient.cs | Introduces stage update client abstraction + subscription reader interface. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/HotChocolate.Fusion.Aspire.csproj | Adds Polly dependency and embeds new operation documents/sidecars. |
| src/HotChocolate/Fusion/src/Fusion.Aspire/GraphQLResourceBuilderExtensions.cs | Ensures auto-update commands are attempted when enabling schema composition on a resource. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| public static IDistributedApplicationBuilder AddNitro( | ||
| this IDistributedApplicationBuilder builder, | ||
| string stage, | ||
| Action<NitroSeedUpdateOptions> configureSeedUpdates, | ||
| Uri? portalUrl = null) |
| UpdateState = context => | ||
| { | ||
| var service = context.ServiceProvider.GetService<NitroSeedUpdateService>(); | ||
| if (service is null || !service.IsEnabled) | ||
| { |
| var filePath = IOPath.Combine( | ||
| _runSeedDirectory, | ||
| $"{gatewayName}.{Interlocked.Increment(ref _nextRunSeedId):D8}.far"); | ||
|
|
||
| File.Copy(seedFilePath, filePath, overwrite: true); |
| var options = SchemaCompositionRegistration.Ensure(builder); | ||
| configureSeedUpdates?.Invoke(options.SeedUpdates); | ||
|
|
||
| if (options.Coordinator is { } coordinator) | ||
| { |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 27 out of 27 changed files in this pull request and generated no new comments.
Suppressed comments (1)
src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroSeedCoordinator.cs:590
ComputeSchemaHashAsynconly catchesIOException, butFusionArchive.TryGetGatewayConfigurationAsync(...)can throwInvalidOperationExceptionwhen the archive metadata has no supported gateway formats (e.g., older/partial archives). That would cause seed acquisition/refresh to fail instead of falling back to hashing the whole archive as the comment intends.
private static async Task<string> ComputeSchemaHashAsync(
string archivePath,
CancellationToken cancellationToken)
{
try
{
using var archive = FusionArchive.Open(archivePath);
using var configuration = await archive.TryGetGatewayConfigurationAsync(
WellKnownVersions.LatestGatewayFormatVersion,
cancellationToken);
if (configuration is not null)
{
await using var schema = await configuration.OpenReadSchemaAsync(cancellationToken);
return Convert.ToHexString(await SHA256.HashDataAsync(schema, cancellationToken));
}
}
catch (IOException)
{
// A seed produced by an older Nitro version can contain only source configurations.
// Hashing the complete immutable archive still gives the refresh path a stable guard.
}
Patch coverage75.6% of changed lines covered (977/1293) Uncovered changed lines (JSON){
"sha": "2a02fa2373a1151ccb1ac9ad43dec588360b203d",
"files": [
{ "path": "src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroSeedUpdateNotifier.cs", "ranges": [[15, 18], [21, 21], [23, 23], [26, 29], [32, 33], [36, 36], [38, 52]] },
{ "path": "src/HotChocolate/Fusion/src/Fusion.Aspire/SchemaComposition.cs", "ranges": [[680, 688], [690, 690], [706, 711], [766, 768], [781, 783], [785, 792], [811, 815], [823, 827], [829, 833], [835, 841], [844, 847], [849, 852], [854, 855]] },
{ "path": "src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroSeedUpdateMonitor.cs", "ranges": [[121, 122], [130, 137], [139, 151], [155, 161], [180, 180], [184, 190], [242, 244], [277, 279], [281, 284], [309, 315], [335, 336], [344, 346], [348, 351], [357, 357], [372, 376], [380, 382], [392, 394], [407, 408], [416, 422], [440, 440], [442, 445], [447, 447], [449, 454], [457, 457], [460, 463], [466, 468]] },
{ "path": "src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroSeedUpdateService.cs", "ranges": [[88, 89], [99, 100], [116, 116], [119, 121], [123, 125], [128, 128], [130, 132], [150, 158], [183, 184], [186, 188], [190, 196], [210, 210]] },
{ "path": "src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroStageSnapshot.cs", "ranges": [[55, 58], [65, 75], [78, 82]] },
{ "path": "src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroStageUpdateClient.cs", "ranges": [[47, 47], [49, 52], [55, 57], [95, 96], [100, 101], [116, 117], [178, 179], [226, 227], [232, 236], [240, 246], [256, 257]] },
{ "path": "src/HotChocolate/Fusion/src/Fusion.Aspire/NitroExtensions.cs", "ranges": [[302, 303], [311, 318]] },
{ "path": "src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroSeedUpdateState.cs", "ranges": [[15, 15], [19, 19]] },
{ "path": "src/HotChocolate/Fusion/src/Fusion.Aspire/Nitro/NitroSeedCoordinator.cs", "ranges": [[346, 348], [396, 397], [455, 456], [516, 517], [540, 540], [580, 585], [602, 605]] }
]
}Project coverage: 54.3% (237219/437108 lines) |
No description provided.