Avoid ephemeral executable target port collisions - #19822
Conversation
Allocate proxied executable target ports from Aspire's non-ephemeral range while preserving dynamic DCP proxy listeners. Ensure isolated runs ignore and never persist proxyless port assignments. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2d6d0570-377a-4d4c-ba04-4cdbf029090c
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 19822Or
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 19822" |
Tests selector49 / 99 PR test projects · 3 PR jobs · 2 advisory-only targets, from 5 changed files. Selected PR test projects (49 / 99)
Selected PR jobs (3)
Advisory workflow impact (2)
How these were chosen — grouped by what changed
🔧 show 45
🧪 📦 affected project 🧪 Job reasons
Selection computed for commit |
There was a problem hiding this comment.
Pull request overview
Prevents executable target ports from colliding with ephemeral ports during DCP startup.
Changes:
- Allocates proxied executable target ports from Aspire’s non-ephemeral range.
- Excludes fixed ports and assigns unique ports to replicas.
- Avoids persisted proxyless ports during isolated runs.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
src/Aspire.Hosting/Dcp/DcpExecutor.cs |
Adds target-port allocation and isolated persistence behavior. |
src/Aspire.Hosting/Dcp/DcpOptions.cs |
Documents expanded port-range usage. |
src/Aspire.Hosting/Dcp/ProxylessEndpointPortAllocator.cs |
Supports allocation without an endpoint identity. |
tests/Aspire.Hosting.Tests/Dcp/DcpExecutorTests.cs |
Covers allocation, exclusions, replicas, and isolation. |
tests/Aspire.Hosting.Tests/Dcp/ProxylessEndpointPortAllocatorTests.cs |
Verifies unique protocol-based allocations. |
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
PR Testing ReportPR Information
Artifact Version Verification
Changes AnalyzedFiles Changed
Change Categories
Test Scenarios ExecutedScenario 1: PR artifact identityObjective: Confirm that testing uses the CLI artifact built from the current PR head. Coverage Type: Artifact verification Status: Passed Evidence:
Observations:
Scenario 2: Single isolated dashboardObjective: Verify an isolated AppHost keeps its dashboard healthy while assigning executable target ports outside the ephemeral range. Coverage Type: Happy path Status: Passed Steps:
Evidence:
Observations:
Scenario 3: Concurrent isolated AppHostsObjective: Verify concurrent isolated AppHosts receive distinct non-ephemeral dashboard target ports without collisions. Coverage Type: Concurrency/boundary Status: Passed Steps:
Evidence:
Observations:
Scenario 4: Isolated persistent port handlingObjective: Verify isolated mode ignores a persisted proxyless port and does not write the newly selected port to either user-secret store. Coverage Type: Unhappy path/boundary Status: Passed Steps:
Evidence:
Observations:
Expected Unhappy-Path Outcome: Isolated mode must select a fresh port without overwriting or reusing the persisted value. Scenario 5: Hosting regression testsObjective: Exercise DCP executor behavior and the non-ephemeral allocator directly. Coverage Type: Unit/integration regression Status: Passed Command: dotnet test --project tests/Aspire.Hosting.Tests/Aspire.Hosting.Tests.csproj --no-launch-profile -- \
--filter-class "*.DcpExecutorTests" \
--filter-class "*.ProxylessEndpointPortAllocatorTests" \
--filter-not-trait "quarantined=true" \
--filter-not-trait "outerloop=true"Evidence:
Observations:
Summary
Overall ResultPR VERIFIED |
|
✅ No documentation update needed. Step 5 branch taken: Triggered signals: none (signal_count: 0, recommendation: docs_optional). Why internal_refactor fits: All 3 non-test files changed (src/Aspire.Hosting/Dcp/DcpExecutor.cs, src/Aspire.Hosting/Dcp/DcpOptions.cs, src/Aspire.Hosting/Dcp/ProxylessEndpointPortAllocator.cs) are internal DCP orchestration implementation details. Per the PR checklist, no public API was added. The change fixes an internal race condition in how DCP allocates ephemeral/proxyless target ports for executable resources before handing them to the child process/DCP proxy - it does not introduce or change any documented public type, method, CLI option, configuration key, environment variable, or user-facing string. The remaining 2 changed files are test-only (tests/Aspire.Hosting.Tests/Dcp/DcpExecutorTests.cs, tests/Aspire.Hosting.Tests/Dcp/ProxylessEndpointPortAllocatorTests.cs). No user-visible behavior, default, error message, environment variable, or config key that the docs site describes is changed by this PR - it is a correctness fix inside DCP's internal port-allocation bookkeeping. No docs PR is warranted. |
Description
DCP dynamically allocated executable target ports by briefly reserving an ephemeral port, releasing it, and later passing it to the child process. Outbound connections could claim that port during the gap, causing workloads such as the Aspire dashboard to fail binding during isolated startup.
This change allocates unspecified target ports for proxied executables from Aspire's existing non-ephemeral port range while leaving DCP-owned dynamic proxy listeners on ephemeral ports. Fixed target ports are excluded from allocation, replicas receive distinct ports, and isolated runs ignore persisted proxyless ports and never write new port assignments to user secrets.
Fixes #19691
Checklist
<remarks />and<code />elements on your triple slash comments?