Add proxyless endpoint port allocator#17924
Conversation
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 17924Or
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 17924" |
PR Testing ReportPR Information
CLI Version Verification
Changes AnalyzedChange Categories
Test Scenarios ExecutedScenario 1: Proxyless executable endpointsObjective: Verify undefined proxyless executable endpoints receive non-ephemeral public ports and persistent executable endpoints keep their port across restart and a fresh AppHost start. Evidence:
Observations: The non-persistent executable received a new allocated port on the second AppHost start. The persistent executable reused the same allocated port across restart and across a fresh AppHost start. Scenario 2: Proxyless container endpointsObjective: Verify undefined proxyless container endpoints use Aspire-assigned host ports, and a persistent container keeps its assigned host port across restart and a fresh AppHost start. Evidence:
Observations: Both container endpoints received host ports in the stable allocator range, and the persistent container reused its host port across restart and a fresh AppHost start. Scenario 3: Two persistent Azure Storage emulatorsObjective: Verify multiple persistent Azure Storage emulator resources can allocate distinct proxyless endpoint ports and reuse them on a fresh AppHost start. Evidence:
Observations: The two emulators received distinct Blob/Queue/Table ports and reused the exact same port sets on the second AppHost start. Scenario 4: Fixed-port pre-exclusion with constrained rangeObjective: Verify a fixed proxyless public port is excluded from allocator candidates so a dynamic proxyless endpoint does not collide with it. Setup: Evidence:
Observations: The fixed endpoint used port 12000, and the dynamic endpoint used the only remaining port, 12001. Scenario 5: Invalid configured port rangeObjective: Verify invalid Expected Outcome: Non-zero exit with a clear validation error. Evidence:
Setup NotesAn initial attempt used Summary
Overall ResultPR VERIFIED The tested proxyless endpoint allocation behaviors worked as expected for executables, containers, fixed-port exclusion, invalid range validation, and persistent Azure Storage emulator resources. |
There was a problem hiding this comment.
Pull request overview
This PR makes proxyless endpoints (those with isProxied: false) behave consistently in run mode when no explicit public/host port is provided, by allocating a stable host port during DCP service preparation for both executables and containers. It centralizes allocation in a single allocator, removes the old on-demand endpoint allocation path, and adds persistence of allocated ports for persistent resources via user secrets.
Changes:
- Introduces
ProxylessEndpointPortAllocatorand wires it into DCP service preparation to allocate undefined proxyless public ports from a configurable range (default10000-32767). - Persists allocated proxyless ports for persistent resources via user secrets and reuses them on later runs; updates tests to validate stable ports/URLs across runs and restarts.
- Removes the on-demand endpoint allocation annotation/path and updates endpoint resolution + DCP watcher/model utilities accordingly.
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Aspire.Hosting.Tests/Utils/PersistentContainerTestHelpers.cs | Extends persistent-container reuse helper to optionally compare stable URLs/ports and handle multiple resources. |
| tests/Aspire.Hosting.Tests/Utils/MockUserSecretsManager.cs | Captures secrets written/deleted so tests can assert port persistence behavior. |
| tests/Aspire.Hosting.Tests/EndpointReferenceTests.cs | Removes on-demand endpoint allocation tests and helper now that the mechanism is deleted. |
| tests/Aspire.Hosting.Tests/DistributedApplicationTests.cs | Updates expectations: proxyless endpoints without an explicit port are now allocated (no longer throw). |
| tests/Aspire.Hosting.Tests/Dcp/ProxylessEndpointPortAllocatorTests.cs | Adds focused unit tests for allocator candidate selection, exclusions, and reservations. |
| tests/Aspire.Hosting.Tests/Dcp/DcpExecutorTests.cs | Adds/updates DCP executor tests for allocated proxyless ports, persistence, exclusions, and restart stability. |
| tests/Aspire.Hosting.Tests/Dcp/DcpCliArgsTests.cs | Adds validation + config override tests for ASPIRE_PROXYLESS_ENDPOINT_PORT_RANGE. |
| tests/Aspire.Hosting.Azure.Tests/AzureStorageEmulatorFunctionalTests.cs | Updates persistence test to assert containers and ports/URLs are stable across runs. |
| src/Shared/KnownConfigNames.cs | Adds ASPIRE_PROXYLESS_ENDPOINT_PORT_RANGE known config constant. |
| src/Aspire.Hosting/DistributedApplicationBuilder.cs | Registers ProxylessEndpointPortAllocator as a singleton for DCP usage. |
| src/Aspire.Hosting/Dcp/ProxylessEndpointPortAllocator.cs | New allocator: scans a stable range, probes port availability, excludes ports, and reserves per-endpoint allocations. |
| src/Aspire.Hosting/Dcp/DcpResourceWatcher.cs | Removes “publish endpoints allocated” callback path; watcher now just applies observed service address info to endpoints. |
| src/Aspire.Hosting/Dcp/DcpOptions.cs | Adds port range options, validation, and parsing of ASPIRE_PROXYLESS_ENDPOINT_PORT_RANGE. |
| src/Aspire.Hosting/Dcp/DcpModelUtilities.cs | Removes dynamic proxyless container on-demand allocation path; simplifies service address application. |
| src/Aspire.Hosting/Dcp/DcpExecutor.cs | Allocates undefined proxyless endpoint ports during service prep; persists/reuses for persistent lifetimes; removes delayed allocation flow. |
| src/Aspire.Hosting/Dcp/ContainerCreator.cs | Stops interacting with removed on-demand allocation annotation during container configuration. |
| src/Aspire.Hosting/ApplicationModel/OnDemandEndpointAllocationAnnotation.cs | Deletes the annotation type used for on-demand endpoint allocation. |
| src/Aspire.Hosting/ApplicationModel/EndpointReference.cs | Removes on-demand allocation behavior from endpoint resolution; waits only for allocated endpoint snapshots. |
Add a stateful allocator for proxyless endpoints without an explicit public port, including fixed-port pre-exclusion, configurable allocation range, persistent-resource port reuse through user secrets, and removal of delayed on-demand endpoint allocation callbacks. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Update stale proxyless endpoint coverage to expect Aspire-assigned ports and prevent DCP watcher service changes from publishing endpoint allocation events during startup. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Make the test port-availability helper use the allocator's actual IPv4+IPv6 probe so it can't hand back a port the allocator rejects, and randomize the scan start so parallel tests don't converge on the same single-port ranges (flaky-test fixes). - Remove the vestigial bool/out contract on TryApplyServiceAddressToEndpoint (always returned false): rename to ApplyServiceAddressToEndpoint, drop the dead endpoint-allocated publish branch and now-unused watcher plumbing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
5a601bc to
b3adb7b
Compare
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Re-running the failed jobs in the CI workflow for this pull request because 1 job was identified as retry-safe transient failures in the CI run attempt.
|
karolz-ms
left a comment
There was a problem hiding this comment.
Looks good overall, just some minor issues/code clarity suggestions
Co-authored-by: Karol Zadora-Przylecki <karolz@microsoft.com>
Co-authored-by: Karol Zadora-Przylecki <karolz@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
❓ CLI E2E Tests unknown — 113 passed, 0 failed, 2 unknown (commit View all recordings
📹 Recordings uploaded automatically from CI run #27046884362 |
Description
Proxyless endpoints without explicit public ports currently have inconsistent run-mode behavior: executable endpoints can fail validation, while container endpoints can depend on delayed allocation. This PR gives DCP a single allocation path for undefined proxyless public ports so both resource types get predictable host ports before workload creation.
The implementation adds a singleton proxyless endpoint port allocator that scans a configurable stable port range, pre-excludes fixed public ports, and tracks allocator-assigned ports to avoid duplicates. Persistent resources store dynamically assigned proxyless public ports in user secrets and reuse them on later runs; if persistence fails, Aspire logs a warning that explains how to avoid recreating the persistent resource each run. The old delayed on-demand endpoint allocation callback path is removed.
User-facing usage
Proxyless endpoints without an explicit public port now get an assigned public port during DCP service preparation:
The default allocation range is
10000-32767. It can be overridden with:Persistent resources reuse the assigned port from user secrets when available.
Breaking changes
This changes proxyless endpoint allocation timing and behavior in run mode. Code or tests that expected executable proxyless endpoints without a public port to fail, or expected container proxyless public ports to be allocated later by DCP/container startup, should update to expect Aspire to assign the public port during service preparation.
Security considerations
This change assigns host public ports for proxyless endpoints and can persist selected port numbers in user secrets for persistent resources. The allocator probes candidate ports only to determine availability, and stored user-secrets values are port numbers rather than credentials.
Fixes # (issue)
Checklist
<remarks />and<code />elements on your triple slash comments?