Fix Dapr sidecar env callback crashing aspire run with Azure resources by deferring endpoint port resolution#1459
Open
gabynevada wants to merge 1 commit into
Conversation
In run mode, `AddAzureContainerAppEnvironment` registers an `azure-prepare-resources` before-start step that walks each compute resource and fires its environment callbacks to discover Azure role-assignment references — before DCP allocates endpoints. The Dapr lifecycle hook's callback eagerly read the auto-generated `<name>-dapr-cli` sidecar's http/grpc endpoint `.Port`, throwing "The endpoint `http` is not allocated for the resource `<name>-dapr-cli`" and crashing the AppHost before anything boots (microsoft/aspire#18242). Defer the port via `EndpointReference.Property(EndpointProperty.Port)` so the discovery walk collects it as a raw reference without resolving; it still resolves to the correct allocated proxy port after allocation. Add regression tests in Dapr.Tests (no Azure) and Azure.Dapr.Tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/CommunityToolkit/Aspire/main/eng/scripts/dogfood-pr.sh | bash -s -- 1459Or
iex "& { $(irm https://raw.githubusercontent.com/CommunityToolkit/Aspire/main/eng/scripts/dogfood-pr.ps1) } 1459" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1458
Overview
In run mode, when an AppHost uses Azure resources,
AddAzureContainerAppEnvironmentregisters anazure-prepare-resourcesbefore-start step. That step walks each compute resource and eagerly fires itsEnvironmentCallbackAnnotationcallbacks to discover Azure role-assignment references — before DCP allocates endpoints.The Dapr lifecycle hook attaches an environment callback to the app resource that eagerly read the auto-generated
<name>-dapr-clisidecar'shttp/grpcendpoint.Port:EndpointReference.Portblocks on the resolved allocated value and throwsInvalidOperationException: The endpoint 'http' is not allocated for the resource '<name>-dapr-cli'when invoked before allocation — crashing the whole AppHost (exit 134) before anything boots.Root cause & fix
The two lines above are the only eager endpoint reads in this run-mode path (the sibling
DAPR_GRPC_ENDPOINT/DAPR_HTTP_ENDPOINTentries already add theEndpointReferenceobject directly as a deferredIValueProviderand never threw; thedaprClicommand-line-args callback already uses deferred.Property(EndpointProperty.TargetPort)and is guarded byIsAllocated). The fix replaces the eager reads with a deferred reference expression:EndpointReference.Property(EndpointProperty.Port)returns anEndpointReferenceExpression(IValueProvider) that the discovery walk collects as a raw reference without resolving, so it no longer throws at before-start — and it still resolves to the same allocated proxy port (DAPR_HTTP_PORT="3500"/DAPR_GRPC_PORT="50001") later.EndpointProperty.Port(the proxy/host port the app connects to) is the correct value here, unchanged from the previous behavior — the CLI args separately useTargetPortfor the container-internal port. The now-unusedusing System.Globalization;was removed to keep the build warning-clean.This is a non-breaking bug fix. The change is confirmed by the upstream maintainer (microsoft/aspire#18242, closed as by-design — the fix belongs in this repo) and follows the same "defer resolution" precedent already applied to this file in #959.
Tests
A deterministic regression test was added (no Docker, no Azure provisioning):
DaprSidecarEndpointAllocationTests.AppEnvironmentCallback_DoesNotThrow_WhenDaprSidecarEndpointsNotAllocateddrives the exact failing operation —GetResourceDependenciesAsync(..., ResourceDependencyDiscoveryMode.DirectOnly), the same callAzureResourcePreparer.PrepareResourcesAsyncmakes per compute resource — with the sidecar endpoints unallocated. It fails with the exact "is not allocated" exception on the pre-fix code and passes on the fix, and additionally asserts the port env vars are present as deferredIValueProviders (guarding against a silent no-op). A secondary end-to-end guard in the Azure test project (DaprAzureContainerAppEnvironmentTests) pins the reported topology usingAddAzureContainerAppEnvironment+WithDaprSidecar.Full
CommunityToolkit.Aspire.Hosting.Dapr.Testssuite (net10.0, CI filter): 37 total, 32 passed, 0 failed, 5 pre-existing/unrelated skips.PR Checklist
fix/dapr-defer-sidecar-endpoint-portOther information
noneseverity and one returnedlow. Correctness/regression confirmed (via decompiled Aspire 13.4.3) that the deferred path resolves to the byte-identical env value the eager read produced (same allocated proxy port, same InvariantCulture formatting →3500/50001), publish/manifest mode is unaffected (callback early-returns onIsPublishMode), and no consumer depends on a plain-string value at gather time. Completeness confirmed the two fixed lines were the only unguarded eager endpoint reads in the run-mode path. The singlelowfinding was optional test hardening — an active test asserting the post-allocation resolved values — which is intentionally not added: resolving a deferred endpoint port requires a fully-started DCP host (a bare manually-setAllocatedEndpointmakes the resolving API block indefinitely), which is exactly why the existing goldenDaprTeststhat asserts3500/50001is[Skip]-ed. That contract remains documented by the preserved (unmodified) skipped golden test; the new regression test deliberately fires the callback without resolving, matching the real crash path.OpenTelemetryCollectorRoutingExtensions.cseagerly readsendpoint.Urlin aLogDebugcall, throwing the same "not allocated" error under the same Azure prepare-resources walk). It is intentionally not bundled here to keep this PR narrowly scoped and reviewable; it warrants the same one-line deferred-reference fix in a separate PR.