fix(pipelines): retry terraform apply/destroy on transient Azure control-plane conflicts - #1279
Open
Liyu Ma (liyu-ma) wants to merge 1 commit into
Open
fix(pipelines): retry terraform apply/destroy on transient Azure control-plane conflicts#1279Liyu Ma (liyu-ma) wants to merge 1 commit into
Liyu Ma (liyu-ma) wants to merge 1 commit into
Conversation
…rol-plane conflicts Azure serializes control-plane operations on a managed cluster. When another operation is still in flight, ARM rejects the request with a transient conflict such as `409 EtagMismatch` / `PutManagedClusterAndComponents_FailedPrecondition_HCPServerError`, or `(OperationNotAllowed) ... there's an in-progress <X>.PUT operation`. The only protection today is `retryCountOnTaskFailure`, driven by `retry_attempt_count`. Several pipelines deliberately set that to 0 to avoid re-running expensive provisioning - for example `pipelines/perf-eval/Hyperscale Cluster Benchmark/ccp-provisioning-H2.yml` - so they fail immediately on a conflict that clears itself within a minute or two. Hyperscale H2 run 20260803.1 failed exactly this way: the azure_H2 stage died after 36s in "Run Terraform destroy Command" with 409 EtagMismatch. Add a bounded in-script retry with exponential backoff around the terraform apply/destroy invocation: * only retries when cloud is azure and the terraform log matches a known concurrent-operation conflict, so genuine failures (quota, bad config, missing permissions) still fail fast and fall through to the existing cleanup logic unchanged; * defaults to 3 retries with 60s/120s/240s backoff, tunable via the new transient_conflict_retry_count and transient_conflict_retry_delay_seconds parameters; * is independent of retry_attempt_count, so it also protects pipelines that opt out of task-level retries; * logs an Azure DevOps warning on each retry so the conflict stays visible in the run summary. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
For reviewers only: reply |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR improves Azure pipeline reliability by adding a bounded, in-script retry with exponential backoff around terraform apply / terraform destroy when Azure ARM rejects the operation due to transient “another operation in progress” control-plane conflicts. This makes Azure transient conflict handling independent of task-level retries (retryCountOnTaskFailure), which some pipelines disable.
Changes:
- Added new template parameters to control transient conflict retry count and base delay.
- Wrapped the terraform apply/destroy invocation in a retry loop that only triggers for Azure and only when known transient conflict signatures are detected in the terraform log.
- Emitted Azure DevOps warning log issues on each retry to keep conflicts visible in run summaries.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Azure serializes control-plane operations on a managed cluster. When another operation is still in flight, ARM rejects
terraform apply/terraform destroywith a transient conflict:or
The only protection today is
retryCountOnTaskFailure, driven byretry_attempt_count. Several pipelines deliberately set that to 0 to avoid re-running expensive provisioning — e.g.pipelines/perf-eval/Hyperscale Cluster Benchmark/ccp-provisioning-H2.yml— so those pipelines fail immediately on a conflict that clears itself within a minute or two.Observed failures:
20260803.1azure_H2died after 36s in Run Terraform destroy Command — 409EtagMismatch20260802.1azure_uksouth*—OperationNotAllowed(in-progressPutExtensionAddonHandler.PUT), cascading into failed destroy + failed Destroy Resource GroupChange
Bounded in-script retry with exponential backoff around the terraform apply/destroy invocation in
steps/terraform/run-command.yml:cloud == azureand the terraform log matches a known concurrent-operation conflict (EtagMismatch,OperationNotAllowed,AnotherOperationInProgress,Another operation is in progress,in-progress … operation,operation preempted). Genuine failures (quota, bad config, missing permissions) still fail fast and fall through to the existing cleanup logic unchanged.transient_conflict_retry_countandtransient_conflict_retry_delay_secondsparameters.retry_attempt_count, so it also protects pipelines that opt out of task-level retries.Behaviour is unchanged for AWS/GCP and for every non-conflict failure path.
Testing
yamllint -c .yamllint steps/terraform/run-command.yml --no-warnings— clean.bash -n.quota exceeded)cloud == awswith conflict textOperationNotAllowed/ in-progress PUT