-
Notifications
You must be signed in to change notification settings - Fork 854
Publishers crash or silently drop resources when references cross resource boundaries #15900
Description
Problem
Publishers crash or silently drop resources when references cross resource boundaries. This affects all compute environment implementations:
- Docker Compose (
DockerComposeInfrastructure) - Azure Container Apps (
AzureContainerAppsInfrastructure) - Azure App Service
- Kubernetes
- Any 3rd-party implementation that follows the same
BeforeStart+GetComputeResources+ResourceMappingpattern
The root pattern is broken and needs to change.
Root cause
All publishers follow the same pattern:
- Subscribe to
BeforeStartEvent - Iterate
GetComputeResources()(which filters out build-only, excluded, cross-environment resources) - Build a
ResourceMappingdictionary from only those filtered resources - Resolve environment variables — which can reference ANY resource, including filtered ones
- 💥
KeyNotFoundExceptionwhen a callback references a resource not in the mapping
GetComputeResources() makes a premature decision about which resources matter. It conflates "should this resource be deployed" with "should this resource exist in the resolution graph." These are different questions.
Affected publishers
| Publisher | Mapping | Crash site |
|---|---|---|
| Docker Compose | DockerComposeEnvironmentResource.ResourceMapping |
DockerComposeServiceResourceExtensions.ProcessValueAsync:22 |
| Azure Container Apps | ContainerAppEnvironmentContext._containerApps |
BaseContainerAppContext:227 |
| Azure App Service | Similar pattern | Similar crash |
| Kubernetes | Similar pattern | Similar crash |
| 3rd-party | Anyone using GetComputeResources() |
Same |
Scenario 1: Build-only container referenced by another resource
A JavaScript app without a PublishAs* method is build-only. When another resource references it, the publisher crashes.
var frontend = builder.AddViteApp("frontend", "./frontend")
.WithHttpEndpoint(name: "http", targetPort: 3000);
builder.AddContainer("api", "apiimage")
.WithReference(frontend.GetEndpoint("http"));Result: KeyNotFoundException during publish-compose step.
Scenario 2: Excluded resource referenced by another resource
var excluded = builder.AddContainer("auth", "authimage")
.WithHttpEndpoint(name: "http", targetPort: 8080)
.ExcludeFromManifest();
builder.AddContainer("api", "apiimage")
.WithReference(excluded.GetEndpoint("http"));Result: KeyNotFoundException — excluded resource not in mapping.
Scenario 3: Cross-environment resource referenced
var compose1 = builder.AddDockerComposeEnvironment("compose1");
var compose2 = builder.AddDockerComposeEnvironment("compose2");
var db = builder.AddContainer("db", "postgres")
.WithHttpEndpoint(name: "http", targetPort: 5432)
.WithComputeEnvironment(compose2);
builder.AddContainer("api", "apiimage")
.WithComputeEnvironment(compose1)
.WithReference(db.GetEndpoint("http"));Result: KeyNotFoundException — db not in compose1's mapping.
Scenario 4: Build-only container with no consumer (silent omission)
// User forgot .PublishAsStaticWebsite()
builder.AddViteApp("frontend", "./frontend")
.WithExternalHttpEndpoints();
builder.AddContainer("api", "apiimage");Result: PIPELINE SUCCEEDED ✅ but frontend is silently missing from output. No error.
Proposed fix
Dependent on #11787 — infrastructure processing runs in BeforeStartEvent, which is too early.
We need to change the pattern that all publishers follow:
- Move infrastructure processing from
BeforeStartinto pipeline steps — proper ordering, other subscribers can add annotations first - Build the full resource mapping — ALL resources get registered (endpoints only), not just compute resources. References never crash.
- Separate "resolvable" from "deployable" — all resources are resolvable (in the mapping), only compute resources are deployable (get
DeploymentTargetAnnotation, appear in output) - Validate the resource graph — after resolution, check for invalid states:
- Build-only resource not consumed and not explicitly excluded → error with actionable message
- Excluded resource referenced by a deployable resource → error with actionable message
- Update all publishers — Docker Compose first, then replicate to ACA, App Service, K8s
- Document the pattern for 3rd-party implementors
Test cases
4 test cases on branch davidfowl/fix-resource-exclusion in DockerComposeResourceExclusionTests.cs:
ReferencedResourceExcludedFromPublish_ShouldNotCrashReferencedResourceTargetingDifferentEnvironment_ShouldNotCrashReferencedBuildOnlyContainer_ShouldNotCrashUnreferencedBuildOnlyContainer_ShouldFailWithClearError
Related
- Depends on: BeforeStartEvent is too early in the pipeline for ACA / AppService resources to process compute resources #11787 (BeforeStartEvent is too early for infrastructure processing)
- JavaScript pits of failure: https://aspire.dev/deployment/javascript-apps/#pits-of-failure
- Branch with WIP fix + tests:
davidfowl/fix-resource-exclusion