Add persistent executable and project lifetimes#17112
Conversation
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 17112Or
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 17112" |
PR Testing ReportPR Information
Scenarios Executed
Overall ResultPartially verified. The PR CLI artifacts are current and the C# lifetime scenario works end-to-end. The TypeScript generated API surface and type-checking work, but runtime validation was blocked by a general TypeScript/polyglot AppHost local-storage-path failure. Evidence
|
PR testing resultsTested the latest PR build with the dogfood CLI. CLI verification
Scenarios
Notable finding A first TypeScript Re-running from a parent directory with a |
|
Found one case in testing that needs a fix in DCP. Parent scoped persistent containers transition to Unknown instead of Exited: microsoft/dcp#158. |
|
Re-running the failed jobs in the CI workflow for this pull request because 3 jobs were identified as retry-safe transient failures in the CI run attempt.
Matched test failure patterns (1 test)
|
|
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.
|
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>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Regenerate Aspire.Hosting API compatibility suppressions for endpoint API changes and remove the obsolete marker from the container-specific lifetime API while documenting the preferred named lifetime methods. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep public resource endpoint events non-blocking while DCP waits for internal URL processing before creating workloads. Harden annotation access and update regression tests for endpoint allocation ordering. 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>
Introduce shared lifetime annotations and WithLifetimeOf so child resources can mirror container, executable, or project lifetime behavior. Update DCP lifetime resolution and emulator child resource propagation to use the shared model while preserving default emulator behavior unless the container callback is supplied. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use the stable DCP object name as the generated OTLP service instance ID for persistent resources while preserving the random suffix for session resources. Add regression coverage for persistent containers and executables using WithOtlpExporter across app host runs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Refresh polyglot CodeGeneration Verify baselines after rebasing onto latest main. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
7854c08 to
3f77fa6
Compare
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>
Manual PR testing resultsI ran two dogfood test passes against this PR. Run 1: persistent lifetime smoke passCLI tested:
Run 2: focused proxyless endpoint passCLI tested:
Summary: The important container behavior is verified: proxyless persistent container endpoints work with only |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Have you tried using it in the TS apphost? |
|
Hmmm I wonder if this broke OtelLogsReturnsStructuredLogsFromStarterApp |
|
Looks like certs. |
| foreach (var url in urls) | ||
| { | ||
| resource.Annotations.Add(url); | ||
| lock (resource.Annotations) |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Restore the old bool isProxied EndpointAnnotation constructor signatures as forwarding shims so older binaries keep binding while new source can omit isProxied and get the nullable default. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add DCP executor tests proving WithEndpointProxySupport(false) overrides explicitly proxied endpoints for both executable and container resources during resource creation. 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>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ecutable-persistence # Conflicts: # src/Aspire.Hosting/Dcp/DcpExecutor.cs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PR testing reportPR: #17112 - Add persistent executable and project lifetimes CLI version verificationThe PR dogfood installer was invoked, but the expected Windows CLI artifact could not be downloaded from the workflow run referenced by the dogfood instructions. Because the PR CLI could not be installed, the CLI version could not be verified against the PR head commit and no scenarios were executed.
Changes analyzedThis PR changes hosting/DCP lifetime behavior for persistent executables and projects, updates related APIs, snapshots, and playground usage.
Planned scenariosThese scenarios were selected based on the changed files, but were not executed because CLI installation failed first:
Overall: Not verified. Please rerun after the PR dogfood workflow publishes the expected |
…osoft/executable-persistence
Dispatch ResourceEndpointsAllocatedEvent with blocking sequential semantics and remove annotation locks that were only needed for concurrent URL annotation mutation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Regenerate the Aspire.Hosting ATS baseline and non-TypeScript CodeGeneration snapshots for the container lifetime and endpoint proxy surface changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Declare the intentional TypeScript API compatibility break for broadening withEndpointProxySupport from ContainerResource to IResourceWithEndpoints. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Restore the container WithEndpointProxySupport shim as an extension method and avoid ambiguity with the generalized endpoint-capable overload by routing through typed C# overloads and a shared implementation. 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 — 96 passed, 0 failed, 2 unknown (commit View all recordings
📹 Recordings uploaded automatically from CI run #26191032628 |
Description
Persistent resources need stable process, endpoint, and environment behavior across AppHost/DCP restarts. This PR adds first-class persistent lifetime support for executable and project resources, keeps the existing container lifetime behavior aligned with the same shared lifetime model, and updates the DCP executable model with
persistent,start, andstopfields matching container behavior.The DCP and hosting changes cover:
Executableresources, not IDE-executed resources.Processhandles.portfromtargetPort(and vice versa) when one is specified, but still require a concrete port value because automatically persisted random executable ports are not designed yet.targetPortand no publicportcan now receive a DCP-allocated host port and publish that allocation when it becomes available.ResourceEndpointsAllocatedEventnotifications as endpoints become available, and URL/dashboard snapshot updates are processed from that public event path for both DCP and integration-generated events.User-facing usage
Consumers can opt executable, project, and container resources into lifetime behavior with the shared resource-level APIs:
WithSessionLifetime,WithPersistentLifetime,WithLifetimeOf, andWithParentProcessLifetimeare the shared lifetime APIs. These shared APIs are marked experimental with diagnosticASPIREPERSISTENCE001while this lifetime model is evaluated. Existing container-specific lifetime APIs remain stable C# compatibility shims, while polyglot AppHost generation now exposes the shared resource-level lifetime APIs.Endpoint proxying now supports a resource-sensitive default.
isProxied: nullallows persistent resources to default to proxyless endpoints while non-persistent resources continue to default to proxied endpoints.Known limitation: non-project executable resources that add an endpoint without a concrete
portortargetPortcan fail when made persistent because persistent endpoints default to proxyless. Persisting initially random-but-overridable ports for those resources needs a separate design.Dashboard/UX note: endpoint URL publication is now explicitly eventual. The dashboard can temporarily show a resource before its endpoint URLs have been allocated/published, and today there is no special pending-endpoint UI beyond an empty URL cell/section. We should consider whether a follow-up UX indicator is warranted for resources that are waiting on endpoint allocation.
Breaking changes
This changes endpoint proxy defaulting semantics by making the public
isProxiedshape nullable and resolving the effective default based on the target resource. Persistent resources default to proxyless endpoints; non-persistent resources continue to default to proxied endpoints. The endpoint proxy support API is generalized so projects, executables, and containers can use the same opt-in/opt-out model. Polyglot lifetime APIs now use shared resource-level lifetime APIs instead of separate resource-specific lifetime shapes.Backward compatibility note: the endpoint builder methods and
EndpointAnnotationconstructors that previously acceptedbool isProxied = trueare preserved as binary-compatible forwarding shims where possible. Assemblies compiled against older Aspire versions that omittedisProxiedstill have the old default value (true) baked into their call sites, so those older binaries keep proxied endpoint behavior when run against this PR. New source compiled against this PR gets the new nullable/default behavior (nullin C#,undefinedfor generated polyglot APIs) whenisProxiedis omitted, allowing the effective default to be computed from the resource lifetime.EndpointAnnotation.IsProxiedremains aboolto preserve the binary signature for assemblies that directly read or write the property. The new nullable configured value is represented separately byEndpointAnnotation.IsExplicitlyProxied. Because the legacyIsProxiedproperty defaults totrueuntil DCP resolves the effective value, very early direct reads can observe the compatibility default rather than the final resource-lifetime-aware value. Reads from later lifecycle points such as resource endpoint allocation, connection string availability, resource start, and environment callbacks should see the resolved effective value.Persistent executable/project resources also no longer support IDE execution or replicas. Persistent resources are rendered for process execution so DCP can own the resource lifetime consistently, and persistent executable/project replicas are rejected with a runtime error rather than attempting to make name-colliding persistent replicas work.
Security considerations
This change affects process lifetime, process execution mode, local endpoint exposure, dev tunnel forwarding, certificate output paths, and environment/OTLP stability. Persistent executable, project, and container DCP resources can include monitor process identity so DCP can scope cleanup to a parent process lifetime; Linux monitor timestamps intentionally use
/proc/<pid>/statprocess identity time rather than wall-clock time to avoid system clock changes. Persistent executable and project resources are constrained to process execution rather than IDE execution, and proxyless persistent endpoints intentionally bind stable local ports that can outlive the AppHost process. Security review should validate the lifetime, endpoint exposure, monitor process, dev tunnel, and certificate path assumptions.Validation performed:
./restore.sh --disable-build-servers./build.sh --build /p:SkipNativeBuild=trueAspire.Hosting.Nats13.3.0 and this PR'sAspire.Hostingsuccessfully constructed the NATS model endpoint withoutMissingMethodExceptiondotnet build src/Aspire.Hosting/Aspire.Hosting.csprojdotnet build playground/Stress/Stress.AppHost/Stress.AppHost.csproj /p:SkipDashboardReference=truedotnet build playground/DevTunnels/DevTunnels.AppHost/DevTunnels.AppHost.csproj /p:SkipNativeBuild=true --no-restoredotnet build tests/Aspire.Hosting.Tests/Aspire.Hosting.Tests.csproj --no-restore /p:SkipNativeBuild=truedotnet build tests/Aspire.Hosting.DevTunnels.Tests/Aspire.Hosting.DevTunnels.Tests.csproj --no-restore /p:SkipNativeBuild=truedotnet build tests/Aspire.Hosting.Azure.Tests/Aspire.Hosting.Azure.Tests.csprojdotnet build tests/Aspire.Hosting.Azure.Kusto.Tests/Aspire.Hosting.Azure.Kusto.Tests.csprojdotnet build tests/Aspire.Hosting.DevTunnels.Tests/Aspire.Hosting.DevTunnels.Tests.csprojdotnet build tests/Aspire.Hosting.PostgreSQL.Tests/Aspire.Hosting.PostgreSQL.Tests.csprojdotnet build tests/Aspire.Hosting.MySql.Tests/Aspire.Hosting.MySql.Tests.csproj./dotnet.sh build src/Aspire.Hosting/Aspire.Hosting.csproj --no-restore /p:SkipNativeBuild=truedotnet test --project tests/Aspire.Hosting.Tests/Aspire.Hosting.Tests.csproj --no-build --no-launch-profile -- --filter-class "*.DcpExecutorTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"dotnet test --project tests/Aspire.Hosting.Tests/Aspire.Hosting.Tests.csproj --no-build --no-launch-profile -- --filter-class "*.ResourceBuilderLifetimeTests" --filter-class "*.ExecutableResourceBuilderExtensionTests" --filter-class "*.ProjectResourceBuilderExtensionTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"dotnet test --project tests/Aspire.Hosting.Tests/Aspire.Hosting.Tests.csproj --no-launch-profile -- --filter-class "*.ResourceBuilderLifetimeTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"dotnet test --project tests/Aspire.Hosting.Tests/Aspire.Hosting.Tests.csproj --no-launch-profile -- --filter-method "*.ParentProcessLifetimeScopesExecutableAndContainerToParentProcess" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"./dotnet.sh test --project tests/Aspire.Hosting.Tests/Aspire.Hosting.Tests.csproj --no-launch-profile -- --filter-class "*.WithEndpointTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"./dotnet.sh test --project tests/Aspire.Hosting.Tests/Aspire.Hosting.Tests.csproj --no-launch-profile -- --filter-class "*.WithUrlsTests" --filter-class "*.DcpExecutorTests" --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"dotnet test --project tests/Aspire.Hosting.DevTunnels.Tests/Aspire.Hosting.DevTunnels.Tests.csproj --no-launch-profile -- --filter-not-trait "quarantined=true" --filter-not-trait "outerloop=true"git diff --checkFixes #6466
Fixes #7046
Fixes #17191
Checklist
<remarks />and<code />elements on your triple slash comments?