Skip to content

Add persistent executable and project lifetimes#17112

Merged
danegsta merged 41 commits into
mainfrom
danegsta-microsoft/executable-persistence
May 20, 2026
Merged

Add persistent executable and project lifetimes#17112
danegsta merged 41 commits into
mainfrom
danegsta-microsoft/executable-persistence

Conversation

@danegsta
Copy link
Copy Markdown
Member

@danegsta danegsta commented May 15, 2026

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, and stop fields matching container behavior.

The DCP and hosting changes cover:

  • Persistent executable and project resources are rendered as process-executed DCP Executable resources, not IDE-executed resources.
  • Persistent executable, project, and container resources use stable DCP instance names and stable OTLP service instance IDs across runs.
  • Persistent executable certificate output paths are stable under the Aspire store.
  • Persistent executable/project resources with replicas are rejected at runtime because persistent replica instances can collide by name.
  • Explicit parent-process lifetime support records only parent process identity data (pid + timestamp) in model annotations and passes that to DCP monitor fields without retaining live Process handles.
  • Endpoint proxy defaults are resource-lifetime aware: persistent resources default to proxyless endpoints, while session resources continue to default to proxied endpoints.
  • Proxyless executable endpoints support inferring port from targetPort (and vice versa) when one is specified, but still require a concrete port value because automatically persisted random executable ports are not designed yet.
  • Proxyless container endpoints with targetPort and no public port can now receive a DCP-allocated host port and publish that allocation when it becomes available.
  • DCP no longer relies on a single deterministic app-wide endpoint allocation phase. It publishes resource-specific ResourceEndpointsAllocatedEvent notifications as endpoints become available, and URL/dashboard snapshot updates are processed from that public event path for both DCP and integration-generated events.
  • Dev tunnel forwarding resolves container endpoints to the allocated host-reachable port instead of the container-internal target port.
  • Azure emulator/surrogate patterns now use shared lifetime propagation helpers where applicable so child resources can match the configured parent/surrogate lifetime.

User-facing usage

Consumers can opt executable, project, and container resources into lifetime behavior with the shared resource-level APIs:

var sessionWorker = builder.AddExecutable("session-worker", "./worker", ".")
    .WithSessionLifetime();

var worker = builder.AddExecutable("worker", "./worker", ".")
    .WithPersistentLifetime();

var api = builder.AddProject<Projects.ApiService>("api")
    .WithEndpointProxySupport(false)
    .WithPersistentLifetime();

var database = builder.AddContainer("database", "postgres")
    .WithPersistentLifetime();

var companion = builder.AddExecutable("companion", "./companion", ".")
    .WithLifetimeOf(database);

var parentProcessId = int.Parse(builder.Configuration["RESOURCE_PARENT_PROCESS_ID"]!);
var scopedWorker = builder.AddExecutable("scoped-worker", "./worker", ".")
    .WithParentProcessLifetime(parentProcessId);

WithSessionLifetime, WithPersistentLifetime, WithLifetimeOf, and WithParentProcessLifetime are the shared lifetime APIs. These shared APIs are marked experimental with diagnostic ASPIREPERSISTENCE001 while 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: null allows persistent resources to default to proxyless endpoints while non-persistent resources continue to default to proxied endpoints.

builder.AddProject<Projects.ApiService>("api")
    .WithEndpoint("https", endpoint =>
    {
        endpoint.IsProxied = null;
    });

Known limitation: non-project executable resources that add an endpoint without a concrete port or targetPort can 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 isProxied shape 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 EndpointAnnotation constructors that previously accepted bool isProxied = true are preserved as binary-compatible forwarding shims where possible. Assemblies compiled against older Aspire versions that omitted isProxied still 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 (null in C#, undefined for generated polyglot APIs) when isProxied is omitted, allowing the effective default to be computed from the resource lifetime.

EndpointAnnotation.IsProxied remains a bool to preserve the binary signature for assemblies that directly read or write the property. The new nullable configured value is represented separately by EndpointAnnotation.IsExplicitlyProxied. Because the legacy IsProxied property defaults to true until 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>/stat process 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=true
  • Targeted DCP endpoint allocation, container endpoint, persistent proxy default, project/executable lifetime, lifecycle, eventing, OTLP stability, parent-process lifetime, replica rejection, and dev tunnel tests
  • DevTunnels playground smoke test confirming persistent project and tunnel processes can remain reachable after AppHost shutdown
  • Scratch compatibility app referencing Aspire.Hosting.Nats 13.3.0 and this PR's Aspire.Hosting successfully constructed the NATS model endpoint without MissingMethodException
  • dotnet build src/Aspire.Hosting/Aspire.Hosting.csproj
  • dotnet build playground/Stress/Stress.AppHost/Stress.AppHost.csproj /p:SkipDashboardReference=true
  • dotnet build playground/DevTunnels/DevTunnels.AppHost/DevTunnels.AppHost.csproj /p:SkipNativeBuild=true --no-restore
  • dotnet build tests/Aspire.Hosting.Tests/Aspire.Hosting.Tests.csproj --no-restore /p:SkipNativeBuild=true
  • dotnet build tests/Aspire.Hosting.DevTunnels.Tests/Aspire.Hosting.DevTunnels.Tests.csproj --no-restore /p:SkipNativeBuild=true
  • dotnet build tests/Aspire.Hosting.Azure.Tests/Aspire.Hosting.Azure.Tests.csproj
  • dotnet build tests/Aspire.Hosting.Azure.Kusto.Tests/Aspire.Hosting.Azure.Kusto.Tests.csproj
  • dotnet build tests/Aspire.Hosting.DevTunnels.Tests/Aspire.Hosting.DevTunnels.Tests.csproj
  • dotnet build tests/Aspire.Hosting.PostgreSQL.Tests/Aspire.Hosting.PostgreSQL.Tests.csproj
  • dotnet build tests/Aspire.Hosting.MySql.Tests/Aspire.Hosting.MySql.Tests.csproj
  • ./dotnet.sh build src/Aspire.Hosting/Aspire.Hosting.csproj --no-restore /p:SkipNativeBuild=true
  • dotnet 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"
  • Polyglot code generation snapshot tests for TypeScript, Python, Java, Go, and Rust
  • git diff --check

Fixes #6466
Fixes #7046
Fixes #17191

Checklist

  • Is this feature complete?
    • Yes. Ready to ship.
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
    • No
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
        • No
    • No
  • Does the change make any security assumptions or guarantees?
    • Yes
      • If yes, have you done a threat model and had a security review?
        • Yes
        • No
    • No

@danegsta danegsta added the breaking-change Issue or PR that represents a breaking API or functional change over a prerelease. label May 15, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 15, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 17112

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 17112"

@danegsta
Copy link
Copy Markdown
Member Author

PR Testing Report

PR Information

Scenarios Executed

Scenario Status Notes
CLI dogfood install/version Passed Installed from the PR dogfood script and matched ea6aa58d.
C# executable lifetime smoke Passed Single-file C# AppHost started/stopped with WithSessionLifetime, WithPersistentLifetime, and WithParentProcessLifetime(Environment.ProcessId). Describe showed all three executable resources running; fixed endpoints were available at tcp://localhost:18080 and tcp://localhost:18081.
TypeScript SDK surface and compile Passed Generated TypeScript SDK contains withPersistentLifetime() and withParentProcessLifetime(parentProcessId: number) on executable resources. A TypeScript AppHost using the lifetime calls passed eslint and tsc.
TypeScript AppHost runtime Blocked aspire start failed before resource startup with Could not determine an appropriate location for local storage. Set the Aspire:Store:Path setting.... A session-only TypeScript executable AppHost failed the same way, so this appears to be a broader polyglot/runtime storage issue rather than specific to persistent lifetime calls.

Overall Result

Partially 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

  • local-install.log
  • local-short-csharp-apphost-after.cs
  • local-short-csharp-describe-summary.json
  • local-short-typescript-apphost-persistent-attempt.ts
  • local-short-typescript-apphost-session-only.ts
  • local-short-typescript-run-report.txt
  • local-short-typescript-session-only-report.txt
  • local-short-typescript-start-failure-excerpt.txt
  • local-short-typescript-lifetime-grep.txt
  • local-short-typescript-parent-lifetime-grep.txt

@danegsta
Copy link
Copy Markdown
Member Author

PR testing results

Tested the latest PR build with the dogfood CLI.

CLI verification

  • Expected PR head: f6766fb6d8e1a3b81606cf6dfe5eb96a24784fa6
  • Installed CLI: 13.4.0-pr.17112.gf6766fb6
  • Result: ✅ matched the PR head short SHA

Scenarios

  • C# file-based AppHost with a persistent explicit-start executable and persistent PostgreSQL container.
    • worker started from NotStarted via aspire resource worker start and reached Running/Healthy.
    • pg reached Running/Healthy and exposed a dynamic TCP URL.
    • resource stop and aspire stop completed successfully.
  • TypeScript/polyglot AppHost using the PR package hive.
    • Restored PR codegen packages, generated .modules, and ran a persistent explicit-start executable.
    • tsworker started from NotStarted, reached Running/Healthy, and stopped cleanly.
    • Persistent executable cert artifacts resolved under the AppHost workspace .aspire/dcp/executables/..., not under .aspire/integrations/.../obj/.aspire.

Notable finding

A first TypeScript aspire new attempt using only --source <PR hive> restored public preview integration/codegen packages (13.4.0-preview.1.26229.5) for the polyglot server and failed with:

Could not load type 'Aspire.TypeSystem.AtsJsonCodeWriter' from assembly 'Aspire.TypeSystem, Version=42.42.42.42'

Re-running from a parent directory with a NuGet.config pointing at the PR hive restored Aspire.TypeSystem and Aspire.Hosting.CodeGeneration.TypeScript as 13.4.0-pr.17112.gf6766fb6, and the TypeScript scenario passed. This looks like an important dogfood/testing setup detail for polyglot scenarios: the template source alone was not enough to force the AppHost integration restore to use the PR packages.

@danegsta
Copy link
Copy Markdown
Member Author

Found one case in testing that needs a fix in DCP. Parent scoped persistent containers transition to Unknown instead of Exited: microsoft/dcp#158.

@github-actions
Copy link
Copy Markdown
Contributor

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.
GitHub was asked to rerun all failed jobs for that attempt, and the rerun is being tracked in the rerun attempt.
The job links below point to the failed attempt jobs that matched the retry-safe transient failure rules.

Matched test failure patterns (1 test)
  • Aspire.Cli.EndToEnd.Tests.KubernetesDeployWithPostgresTests.DeployK8sWithPostgres — Unable to access container registry during publish

@github-actions
Copy link
Copy Markdown
Contributor

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.
GitHub was asked to rerun all failed jobs for that attempt, and the rerun is being tracked in the rerun attempt.
The job links below point to the failed attempt jobs that matched the retry-safe transient failure rules.

danegsta and others added 15 commits May 18, 2026 12:19
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>
@danegsta danegsta force-pushed the danegsta-microsoft/executable-persistence branch from 7854c08 to 3f77fa6 Compare May 18, 2026 19:26
danegsta and others added 4 commits May 18, 2026 13:16
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>
@danegsta
Copy link
Copy Markdown
Member Author

Manual PR testing results

I ran two dogfood test passes against this PR.

Run 1: persistent lifetime smoke pass

CLI tested: 13.4.0-pr.17112.g1f265e06 (1f265e06de4bbbc3324875cd54039f911c6f8938)

Scenario Result Notes
Persistent executable + project reuse across AppHost restart ✅ Passed Executable PID/port stayed stable: 430/31001; project PID/port stayed stable: 536/31002.
Config-change replacement for executable + project ✅ Passed Changing config from alpha to beta replaced executable/project instances: 430/5361580/1664; old instances exited.
Parent-process scoped lifetime ✅ Passed Executable/project persisted after AppHost stop, then cleaned up when the monitored parent process exited.
Persistent container reuse with explicit host port ✅ Passed nginx:alpine container ID stayed stable across AppHost restart: 0611f39366ff.
Persistent container config-change replacement with explicit host port ✅ Passed Config change replaced container 0611f39366ff with f80f1016dec6; old container was gone.
TypeScript polyglot API compile ✅ Passed withPersistentLifetime() and withParentProcessLifetime(1) compiled against generated .modules/aspire.ts.

Run 2: focused proxyless endpoint pass

CLI tested: 13.4.0-pr.17112.g2fda9ee5 (2fda9ee5c9acf1f17a7fd24ede5a90ca437d7b76)

Scenario Result Notes
Persistent container, proxyless endpoint, targetPort: 80, no explicit host port ✅ Passed Allocated dynamic host mapping 127.0.0.1:34017.
Same container config across AppHost restart ✅ Passed Reused same container 3a5e702a4f6f and same host mapping.
Changed container config between runs ✅ Passed Replaced old container 3a5e702a4f6f with 4015aa0e9c38, new host mapping 127.0.0.1:38165.
Executable proxyless endpoint without explicit port ✅ Passed AppHost/resource did not remain running; logs showed explicit port required.
Project proxyless endpoint without explicit host port ✅ Expected validation AppHost validation required a port: Service 'proxyless-project' needs to specify a port for endpoint 'http' since it isn't using a proxy. This matches the current project/executable behavior without a DCP proxy dynamic-port mechanism.

Summary: The important container behavior is verified: proxyless persistent container endpoints work with only targetPort and no explicit host port, keep a stable mapping across same-config AppHost restarts, and regenerate on config changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@davidfowl
Copy link
Copy Markdown
Contributor

Have you tried using it in the TS apphost?

@davidfowl
Copy link
Copy Markdown
Contributor

Hmmm I wonder if this broke OtelLogsReturnsStructuredLogsFromStarterApp

@davidfowl
Copy link
Copy Markdown
Contributor

Looks like certs.

foreach (var url in urls)
{
resource.Annotations.Add(url);
lock (resource.Annotations)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sketchy

Comment thread src/Aspire.Hosting/Orchestrator/ApplicationOrchestrator.cs Outdated
Comment thread src/Aspire.Hosting/CompatibilitySuppressions.xml Outdated
danegsta and others added 9 commits May 19, 2026 21:19
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>
@IEvangelist
Copy link
Copy Markdown
Member

PR testing report

PR: #17112 - Add persistent executable and project lifetimes
Base branch: main
Head commit: a260954e374713d7b4cb885c23e58f750b70eedd
Result: Blocked - PR dogfood CLI artifact was unavailable

CLI version verification

The 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.

text Starting download and installation for PR #17112 Using workflow run https://github.com/microsoft/aspire/actions/runs/26181385935 Downloading CLI from GitHub - cli-native-archives-win-x64 ... INSTALL_FAILED: Error: Failed to download artifact 'cli-native-archives-win-x64' from run: 26181385935 . If the workflow is still running then the artifact named 'cli-native-archives-win-x64' may not be available yet. Check at https://github.com/microsoft/aspire/actions/runs/26181385935#artifacts

Changes analyzed

This PR changes hosting/DCP lifetime behavior for persistent executables and projects, updates related APIs, snapshots, and playground usage.

  • playground/AzureAppService/AzureAppService.AppHost/AppHost.cs
  • playground/AzureContainerApps/AzureContainerApps.AppHost/AppHost.cs
  • playground/AzureServiceBus/ServiceBus.AppHost/AppHost.cs
  • playground/AzureVirtualNetworkEndToEnd/AzureVirtualNetworkEndToEnd.AppHost/AppHost.cs
  • playground/Stress/Stress.AppHost/AppHost.cs
  • playground/TestShop/TestShop.AppHost/AppHost.cs
  • playground/TypeScriptAppHost/apphost.ts
  • playground/TypeScriptApps/RpsArena/apphost.ts
  • src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsExtensions.cs
  • src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs
  • src/Aspire.Hosting.DevTunnels/DevTunnelHealthCheck.cs
  • src/Aspire.Hosting.DevTunnels/DevTunnelPortHealthCheck.cs
  • src/Aspire.Hosting.DevTunnels/DevTunnelResource.cs
  • src/Aspire.Hosting.DevTunnels/DevTunnelResourceBuilderExtensions.cs
  • src/Aspire.Hosting.Foundry/HostedAgent/HostedAgentBuilderExtension.cs
  • src/Aspire.Hosting/ApplicationModel/EndpointAnnotation.cs
  • src/Aspire.Hosting/ApplicationModel/EndpointReference.cs
  • src/Aspire.Hosting/ApplicationModel/EndpointUpdateContext.cs
  • src/Aspire.Hosting/ApplicationModel/Lifetime.cs
  • src/Aspire.Hosting/ApplicationModel/PersistenceAnnotation.cs
  • src/Aspire.Hosting/ApplicationModel/ResourceExtensions.cs
  • src/Aspire.Hosting/BuiltInDistributedApplicationEventSubscriptionHandlers.cs
  • src/Aspire.Hosting/CompatibilitySuppressions.xml
  • src/Aspire.Hosting/ContainerResourceBuilderExtensions.cs
  • src/Aspire.Hosting/Dcp/ContainerCreator.cs
  • src/Aspire.Hosting/Dcp/DcpExecutor.cs
  • src/Aspire.Hosting/Dcp/DcpModelUtilities.cs
  • src/Aspire.Hosting/Dcp/DcpNameGenerator.cs
  • src/Aspire.Hosting/Dcp/DcpProcessMonitor.cs
  • src/Aspire.Hosting/Dcp/DcpResourceWatcher.cs
  • ... and 57 more files

Planned scenarios

These scenarios were selected based on the changed files, but were not executed because CLI installation failed first:

  1. Verify the installed PR dogfood Aspire CLI reports the PR head commit.
  2. Create a temp Aspire app with a project and executable using persistent lifetime APIs, run it, and verify the dashboard/runtime state persists as intended across restarts.
  3. Exercise persistent container replacements such as WithPersistentLifetime() for Redis/PostgreSQL and verify generated app model/snapshots remain coherent.
  4. Run targeted hosting tests around resource lifetime, DCP executor, resource snapshots, and executable/project resources.

Overall: Not verified. Please rerun after the PR dogfood workflow publishes the expected cli-native-archives-win-x64 artifact.

danegsta and others added 8 commits May 20, 2026 11:30
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>
@github-actions
Copy link
Copy Markdown
Contributor

CLI E2E Tests unknown — 96 passed, 0 failed, 2 unknown (commit aee7987)

View all recordings
Status Test Recording
AddPackageInteractiveWhileAppHostRunningDetached ▶️ View recording
AddPackageWhileAppHostRunningDetached ▶️ View recording
AgentCommands_AllHelpOutputs_AreCorrect ▶️ View recording
AgentInitCommand_DefaultSelection_InstallsDefaultSkills ▶️ View recording
AgentInitCommand_MigratesDeprecatedConfig ▶️ View recording
AllPublishMethodsBuildDockerImages ▶️ View recording
AspireAddPackageVersionToDirectoryPackagesProps ▶️ View recording
AspireInitSingleFileAppHostRunsViaDotnetRunAppHost ▶️ View recording
AspireInitWithExistingAppHostDirRecreatesMissingNuGetConfigAndPreservesFiles ▶️ View recording
AspireInitWithSolutionFileGeneratesAppHostThatBuildsAgainstChannelHive ▶️ View recording
AspireUpdateRemovesAppHostPackageVersionFromDirectoryPackagesProps ▶️ View recording
AspireUpdateRemovesOrphanAppHostPackageVersionWhenSdkAlreadyCurrent ▶️ View recording
Banner_DisplayedOnFirstRun ▶️ View recording
Banner_DisplayedWithExplicitFlag ▶️ View recording
Banner_NotDisplayedWithNoLogoFlag ▶️ View recording
CertificatesClean_RemovesCertificates ▶️ View recording
CertificatesTrust_WithNoCert_CreatesAndTrustsCertificate ▶️ View recording
CertificatesTrust_WithUntrustedCert_TrustsCertificate ▶️ View recording
ConfigSetGet_CreatesNestedJsonFormat ▶️ View recording
CreateAndRunAspireStarterProject ▶️ View recording
CreateAndRunAspireStarterProjectWithBundle ▶️ View recording
CreateAndRunEmptyAppHostProject ▶️ View recording
CreateAndRunJavaEmptyAppHostProject ▶️ View recording
CreateAndRunJsReactProject ▶️ View recording
CreateAndRunPythonReactProject ▶️ View recording
CreateAndRunTypeScriptEmptyAppHostProject ▶️ View recording
CreateAndRunTypeScriptStarterProject ▶️ View recording
CreateJavaAppHostWithViteApp ▶️ View recording
CreateTypeScriptAppHostWithViteApp_UsesConfiguredToolchain ▶️ View recording
DashboardRunWithOtelTracesReturnsNoTraces ▶️ View recording
DeployK8sBasicApiService ▶️ View recording
DeployK8sWithExternalHelmChart ▶️ View recording
DeployK8sWithGarnet ▶️ View recording
DeployK8sWithMongoDB ▶️ View recording
DeployK8sWithMySql ▶️ View recording
DeployK8sWithPostgres ▶️ View recording
DeployK8sWithRabbitMQ ▶️ View recording
DeployK8sWithRedis ▶️ View recording
DeployK8sWithSqlServer ▶️ View recording
DeployK8sWithValkey ▶️ View recording
DeployTypeScriptAppToKubernetes ▶️ View recording
DescribeCommandResolvesReplicaNames ▶️ View recording
DescribeCommandShowsRunningResources ▶️ View recording
DetachFormatJsonProducesValidJson ▶️ View recording
DetachFormatJsonProducesValidJsonWhenRestartingExistingInstance ▶️ View recording
DoListStepsShowsPipelineSteps ▶️ View recording
DocsCommand_RendersInteractiveMarkdownFromLocalSource ▶️ View recording
DoctorCommand_DetectsDeprecatedAgentConfig ▶️ View recording
DoctorCommand_TypeScriptAppHostReportsMissingConfiguredToolchain ▶️ View recording
DoctorCommand_WithSslCertDir_ShowsTrusted ▶️ View recording
DoctorCommand_WithoutSslCertDir_ShowsPartiallyTrusted ▶️ View recording
GeneratedAspireDevScript_StartsWatchMode_WithConfiguredToolchain ▶️ View recording
GlobalMigration_HandlesCommentsAndTrailingCommas ▶️ View recording
GlobalMigration_HandlesMalformedLegacyJson ▶️ View recording
GlobalMigration_PreservesAllValueTypes ▶️ View recording
GlobalMigration_SkipsWhenNewConfigExists ▶️ View recording
GlobalSettings_MigratedFromLegacyFormat ▶️ View recording
InitTypeScriptAppHost_AugmentsExistingViteRepoAtRoot ▶️ View recording
InteractiveCSharpInitCreatesExpectedFiles ▶️ View recording
InvalidAppHostPathWithComments_IsHealedOnRun ▶️ View recording
JavaScriptHostingApisRunFromTypeScriptAppHost ▶️ View recording
LatestCliCanStartStableChannelAppHost ▶️ View recording
LatestCliCanStartStableChannelTypeScriptAppHost ▶️ View recording
LegacySettingsMigration_AdjustsRelativeAppHostPath ▶️ View recording
LogLevelTrace_ProducesTraceEntriesInCliLogFile ▶️ View recording
LogsCommandShowsResourceLogs ▶️ View recording
OtelLogsReturnsStructuredLogsFromStarterApp ▶️ View recording
OtelLogsReturnsStructuredLogsFromStarterAppIsolated ▶️ View recording
PsCommandListsRunningAppHost ▶️ View recording
PsFormatJsonOutputsOnlyJsonToStdout ▶️ View recording
PublishJavaScriptPatternsGeneratesExpectedDockerComposeArtifacts ▶️ View recording
PublishWithConfigureEnvFileUpdatesEnvOutput ▶️ View recording
PublishWithDockerComposeServiceCallbackSucceeds ▶️ View recording
PublishWithoutOutputPathUsesAppHostDirectoryDefault ▶️ View recording
ResourceCommand_FailedExecution_DisplaysAppHostLogPathAndLogContainsEntries ▶️ View recording
ResourceCommand_FailsWhenInteractionServiceIsRequired ▶️ View recording
ResourceCommand_SetAndDeleteParameterUpdatesDescribeOutput ▶️ View recording
RestoreGeneratesSdkFiles ▶️ View recording
RestoreGeneratesSdkFiles_WithConfiguredToolchain ▶️ View recording
RestoreRefreshesGeneratedSdkAfterAddingIntegration ▶️ View recording
RestoreSupportsConfigOnlyHelperPackageAndCrossPackageTypes ▶️ View recording
RunFromParentDirectory_UsesExistingConfigNearAppHost ▶️ View recording
RunPublishFailureScenarioAsync ▶️ View recording
RunReportsSyntaxErrorsForDotNetAppHost ▶️ View recording
RunReportsSyntaxErrorsForTypeScriptAppHost ▶️ View recording
SecretCrudOnDotNetAppHost ▶️ View recording
SecretCrudOnTypeScriptAppHost ▶️ View recording
StagingChannel_ConfigureAndVerifySettings_ThenSwitchChannels ▶️ View recording
StartAndWaitForTypeScriptSqlServerAppHostWithNativeAssets ▶️ View recording
StartReportsSyntaxErrorsForDotNetAppHost ▶️ View recording
StartReportsSyntaxErrorsForTypeScriptAppHost ▶️ View recording
StopAllAppHostsFromAppHostDirectory ▶️ View recording
StopJavaPolyglotAppHostUsingApphostDirectory ▶️ View recording
StopNonInteractiveSingleAppHost ▶️ View recording
StopTypeScriptPolyglotAppHostUsingApphostDirectory ▶️ View recording
StopWithNoRunningAppHostExitsSuccessfully ▶️ View recording
UnAwaitedChainsCompileWithAutoResolvePromises ▶️ View recording
UpdateProjectChannelToStable_TypeScript_PicksUpStablePackages ▶️ View recording

📹 Recordings uploaded automatically from CI run #26191032628

@danegsta danegsta merged commit 35528b0 into main May 20, 2026
600 of 603 checks passed
@microsoft-github-policy-service microsoft-github-policy-service Bot added this to the 13.4 milestone May 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking-change Issue or PR that represents a breaking API or functional change over a prerelease.

Projects

None yet

4 participants