Skip to content

Serialize same-environment Azure Container Apps deployment#18699

Draft
mitchdenny wants to merge 7 commits into
mainfrom
mitchdenny-aca-serial-deploy-ordering
Draft

Serialize same-environment Azure Container Apps deployment#18699
mitchdenny wants to merge 7 commits into
mainfrom
mitchdenny-aca-serial-deploy-ordering

Conversation

@mitchdenny

Copy link
Copy Markdown
Member

Description

Azure Container Apps serializes write operations per managed environment. Concurrent create/update of apps sharing the same environment fails with ContainerAppOperationInProgress. The aspire deploy pipeline avoids this by deploying resources sequentially, but the application model itself carried no ordering edge — so model-graph-driven deployers (e.g. the internal EV2 pipeline) deploy apps in parallel and hit the error.

This PR expresses that ordering in the model so any deployer that respects the resource dependency graph serializes container app deployments per environment.

Approach

During publish only, AzureContainerAppEnvironmentResource.PrepareDeploymentTargetsAsync chains all compute resources targeted to a managed environment into a single total serial order using DependsOn ResourceRelationshipAnnotation edges:

  1. Collect the environment's deployment targets (model order).
  2. Build the existing-dependency map among them from Reference/WaitFor relationships (same-environment targets only).
  3. Topologically sort dependencies-first, using model order as a stable tie-break (cycle-safe fallback).
  4. For each consecutive pair, add a synthetic DependsOn edge unless the existing graph already orders them transitively — honoring user-declared WithReference/WaitFor dependencies and avoiding redundant edges or cycles.

Result: a single serial chain per environment ⇒ at most one container app deploys at a time per managed environment. No cross-environment edges are added, and run mode is unaffected (the dashboard never sees these edges).

Notes

  • The chain includes jobs as well as apps, since both write into the same managed environment.
  • DependsOn is defined as a local internal const because KnownRelationshipTypes is internal to Aspire.Hosting/Aspire.Hosting.Azure and not visible to Aspire.Hosting.Azure.AppContainers.

Testing

Added 6 tests in AzureContainerAppsTests, including ContainerAppsSharingADependencyAreStillSerialized (verifies the full-serialization guarantee), redundant-edge avoidance, per-environment independence, single-app no-op, and run-mode no-op.

Fixes #18682

Copilot AI review requested due to automatic review settings July 9, 2026 01:52
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

🚀 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 -- 18699

Or

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

@github-actions github-actions Bot added the area-integrations Issues pertaining to Aspire Integrations packages label Jul 9, 2026
@github-actions

This comment has been minimized.

Copilot AI left a comment

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.

Pull request overview

This PR makes Azure Container Apps' per-environment write-lock constraint explicit in the application model. Azure serializes create/update operations within a single managed environment, so parallel model-graph deployers (e.g. the internal EV2 pipeline) currently hit ContainerAppOperationInProgress. During publish only, AzureContainerAppEnvironmentResource.PrepareDeploymentTargetsAsync now chains all compute resources targeted to an environment into a single serial DependsOn order, so any deployer honoring the resource dependency graph deploys at most one app at a time per environment.

The approach is sound: it collects same-environment targets in model order, derives the existing dependency map from Reference/WaitFor relationships, performs a topological sort (model order as a stable tie-break, with a cycle-safe fallback), and adds a synthetic DependsOn edge between consecutive pairs only when the existing graph doesn't already order them — avoiding redundant edges and cycles. Cross-environment edges are never added, and run mode is unaffected (the method returns early when not publishing).

I traced the algorithm through all six test scenarios and confirmed the edges produced match the assertions; the transitive-redundancy check correctly ignores in-progress synthetic edges because each node's only synthetic out-edge is the one being added. I also confirmed ResourceNameComparer.cs is compiled into this assembly, that Reference/WaitFor relationship directions match GetExistingDependencies, and that relationship annotations are not serialized into the bicep/manifest output (so no snapshot tests are impacted).

Changes:

  • Added AddSerialDeploymentOrdering plus GetExistingDependencies, TopologicalSort, and DependsOnTransitively helpers to serialize same-environment container app deployment via synthetic DependsOn relationships (publish-only).
  • Collected the environment's deployment targets during PrepareDeploymentTargetsAsync and invoked the new ordering pass.
  • Added 6 tests covering serial chaining, redundant-edge avoidance, shared-dependency serialization, per-environment independence, single-app no-op, and run-mode no-op.
Show a summary per file
File Description
src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppEnvironmentResource.cs Adds the serial-deployment-ordering logic (topological sort + transitive redundancy check) that injects DependsOn edges among same-environment compute targets during publish.
tests/Aspire.Hosting.Azure.Tests/AzureContainerAppsTests.cs Adds six tests validating the chaining behavior across floating apps, existing dependencies, shared dependencies, multiple environments, single-app, and run mode.

Review details

  • Files reviewed: 2/2 changed files
  • Comments generated: 0
  • Review effort level: Medium

Copilot AI review requested due to automatic review settings July 9, 2026 02:10
@github-actions

This comment has been minimized.

Copilot AI left a comment

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.

Review details

  • Files reviewed: 2/2 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

@mitchdenny

Copy link
Copy Markdown
Member Author

PR Testing Report

PR Information

Artifact Version Verification

  • Expected Commit: 5b5db57
  • Installed Version: 13.5.0-pr.18699.g5b5db574
  • Status: ✅ Verified

Changes Analyzed

Files Changed

  • src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppEnvironmentResource.cs — publish-time serial-ordering edges
  • tests/Aspire.Hosting.Azure.Tests/AzureContainerAppsTests.cs — 7 unit tests

Change Categories

  • Hosting integration changes (Azure Container Apps)
  • CLI / Dashboard / Templates / Components / Extension / CI infra

Testability note

The change adds DependsOn ResourceRelationshipAnnotation edges only in publish mode, consumed by external model-graph deployers (EV2). aspire run is a no-op, and aspire deploy orders via bicep parameter references (not DependsOn), so the ordering behavior is not directly observable through the dogfood CLI. Authoritative validation is the unit suite (7/7 passing against the merged base). This report covers the one CLI-observable scenario: the publish path is exercised and confirmed not to regress or leak.

Test Scenarios Executed

Scenario 1: Publish smoke — ACA env with shared dependency + floating apps

Objective: Exercise the changed publish path (PrepareDeploymentTargetsAsyncAddSerialDeploymentOrdering) end-to-end via the CLI, and confirm generated artifacts are unaffected.
Coverage Type: Happy path
Status: ✅ Passed

AppHost:

builder.AddAzureContainerAppEnvironment("env");
var shared = builder.AddContainer("shared", "myimage");
builder.AddContainer("api", "myimage").WaitFor(shared);
builder.AddContainer("worker", "myimage").WaitFor(shared);
builder.AddContainer("cache", "myimage");
builder.AddContainer("gateway", "myimage");

Steps:

  1. Installed PR CLI (isolated) → version 13.5.0-pr.18699.g5b5db574.
  2. aspire new aspire-empty --language csharp from the PR hive.
  3. Added Aspire.Hosting.Azure.AppContainers, an ACA environment, and 5 container apps (shared dependency + floating).
  4. aspire publish to bicep.

Observations:

  • Publish succeeded — 11/11 pipeline steps green.
  • Exactly one bicep module emitted per app (shared, api, worker, cache, gateway) — no duplication introduced by the ordering pass.
  • No DependsOn/dependsOn leakage in any generated artifact (grep across aspire-output/ returned nothing) — confirms the synthetic edges remain model-only (for EV2), not emitted into Aspire's own bicep.
  • main.bicep wires only env/env-acr infra modules (unchanged); per-app modules are provisioned separately by the deploy pipeline — Aspire's own deploy artifacts are unchanged by the PR.

Summary

Scenario Status Notes
Publish smoke (ACA env, shared dep + floating apps) ✅ Passed One module per app; no DependsOn leakage; artifacts unchanged

Overall Result

✅ PR VERIFIED (for the CLI-observable publish path)

Notes

  • Ordering behavior itself is validated by the unit suite (7/7 passing post-merge with origin/main), including SameEnvironmentContainerAppsFormATotalDeploymentOrder.
  • CI on the PR is fully green (331 checks).

Copilot AI review requested due to automatic review settings July 10, 2026 01:38
@github-actions

This comment has been minimized.

Copilot AI left a comment

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.

Review details

  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Medium

Comment thread src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppEnvironmentResource.cs Outdated
@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@mitchdenny

Copy link
Copy Markdown
Member Author

/deployment-test

@github-actions

Copy link
Copy Markdown
Contributor

🚀 Deployment tests starting on PR #18699...

This will deploy to real Azure infrastructure. Results will be posted here when complete.

View workflow run

@github-actions
github-actions Bot temporarily deployed to deployment-testing July 10, 2026 02:53 Inactive
@github-actions
github-actions Bot temporarily deployed to deployment-testing July 10, 2026 02:53 Inactive
@github-actions
github-actions Bot temporarily deployed to deployment-testing July 10, 2026 02:53 Inactive
@github-actions
github-actions Bot temporarily deployed to deployment-testing July 10, 2026 02:53 Inactive
@github-actions
github-actions Bot temporarily deployed to deployment-testing July 10, 2026 02:53 Inactive
@github-actions
github-actions Bot temporarily deployed to deployment-testing July 10, 2026 02:53 Inactive
@github-actions
github-actions Bot temporarily deployed to deployment-testing July 10, 2026 02:53 Inactive
@github-actions
github-actions Bot temporarily deployed to deployment-testing July 10, 2026 02:53 Inactive
@github-actions
github-actions Bot temporarily deployed to deployment-testing July 10, 2026 02:53 Inactive
@github-actions
github-actions Bot temporarily deployed to deployment-testing July 10, 2026 02:53 Inactive
@github-actions
github-actions Bot temporarily deployed to deployment-testing July 10, 2026 02:53 Inactive
@github-actions
github-actions Bot temporarily deployed to deployment-testing July 13, 2026 05:24 Inactive
@github-actions
github-actions Bot temporarily deployed to deployment-testing July 13, 2026 05:24 Inactive
@github-actions
github-actions Bot temporarily deployed to deployment-testing July 13, 2026 05:24 Inactive
@github-actions
github-actions Bot had a problem deploying to deployment-testing July 13, 2026 05:24 Failure
@github-actions
github-actions Bot temporarily deployed to deployment-testing July 13, 2026 05:24 Inactive
@github-actions
github-actions Bot temporarily deployed to deployment-testing July 13, 2026 05:24 Inactive
@github-actions
github-actions Bot temporarily deployed to deployment-testing July 13, 2026 05:24 Inactive
@github-actions
github-actions Bot temporarily deployed to deployment-testing July 13, 2026 05:24 Inactive
@github-actions
github-actions Bot temporarily deployed to deployment-testing July 13, 2026 05:24 Inactive
@github-actions
github-actions Bot temporarily deployed to deployment-testing July 13, 2026 05:24 Inactive
@github-actions
github-actions Bot temporarily deployed to deployment-testing July 13, 2026 05:24 Inactive
Include pre-existing DependsOn relationships when building the Azure Container Apps serial deployment graph so the generated chain stays cycle-free and idempotent.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 62b6966d-e65e-41be-939d-1ee0c9ebbf30
@github-actions

This comment has been minimized.

Copilot AI left a comment

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.

Review details

  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Medium

Comment thread src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppEnvironmentResource.cs Outdated
Handle mutual-reference cycles and cross-environment transitive ordering
when serializing same-environment container apps. Reachability is computed
over the whole model so an order routed through another environment is
honored, and mutually dependent apps are grouped into a strongly connected
component that is serialized as a unit rather than internally, so no
DependsOn cycle is ever introduced.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 62b6966d-e65e-41be-939d-1ee0c9ebbf30
@github-actions

This comment has been minimized.

Copilot AI left a comment

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.

Review details

  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Medium

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

@github-actions

Copy link
Copy Markdown
Contributor

Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 62b6966d-e65e-41be-939d-1ee0c9ebbf30
@github-actions

This comment has been minimized.

Copilot AI left a comment

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.

Review details

  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Low

Comment thread tests/Aspire.Hosting.Azure.Tests/AzureContainerAppsTests.cs
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 62b6966d-e65e-41be-939d-1ee0c9ebbf30

Copilot AI left a comment

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.

Review details

  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Medium

Comment thread tests/Aspire.Hosting.Azure.Tests/AzureContainerAppsTests.cs
@github-actions

This comment has been minimized.

@mitchdenny

Copy link
Copy Markdown
Member Author

/deployment-test

@github-actions

Copy link
Copy Markdown
Contributor

🚀 Deployment tests starting on PR #18699...

This will deploy to real Azure infrastructure. Results will be posted here when complete.

View workflow run

Container App Jobs are compute resources that write to the same managed
environment as apps, so they participate in the serial deployment chain.
Add a test that makes a chain member a job to lock in that behavior.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 62b6966d-e65e-41be-939d-1ee0c9ebbf30

Copilot AI left a comment

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.

Review details

  • Files reviewed: 2/2 changed files
  • Comments generated: 0 new
  • Review effort level: Low

@github-actions

Copy link
Copy Markdown
Contributor

Tests selector (audit mode)

The full test matrix and all jobs still run in audit mode. The tests and jobs below are what selective CI would run under enforcement.

8 / 100 test projects · 3 jobs, from 2 changed files.

Selected test projects (8 / 100)

Aspire.Hosting.Azure.Kubernetes.Tests, Aspire.Hosting.Azure.Tests, Aspire.Hosting.Blazor.Tests, Aspire.Hosting.CodeGeneration.TypeScript.Tests, Aspire.Hosting.Dotnet.Tests, Aspire.Hosting.Radius.Tests, Aspire.Hosting.Tests, Aspire.Playground.Tests

Selected jobs (3)

deployment-e2e, extension-e2e, typescript-api-compat


How these were chosen — grouped by what changed

🔧 src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppEnvironmentResource.cs (changed source)
1 directly: Aspire.Hosting.Azure.Tests
6 via the project graph: Aspire.Hosting.Blazor.Tests (2 hops), Aspire.Hosting.CodeGeneration.TypeScript.Tests, Aspire.Hosting.Dotnet.Tests (2 hops), Aspire.Hosting.Radius.Tests (2 hops), Aspire.Hosting.Tests, Aspire.Playground.Tests (2 hops)

🧪 tests/Aspire.Hosting.Azure.Tests/AzureContainerAppsTests.cs (changed test)
1 directly: Aspire.Hosting.Azure.Tests
1 via the project graph: Aspire.Hosting.Azure.Kubernetes.Tests

Job reasons

Job Triggered by
deployment-e2e affected project Aspire.Hosting.Azure.AppContainers
extension-e2e src/Aspire.Hosting.Azure.AppContainers/AzureContainerAppEnvironmentResource.cs
• affected project Aspire.Hosting.Azure.AppContainers
typescript-api-compat affected project Aspire.Hosting.Azure.AppContainers

Selection computed for commit 6afa143.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-integrations Issues pertaining to Aspire Integrations packages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Azure Container Apps: express deployment ordering for container apps sharing a managed environment

2 participants