Skip to content

{App Service} az webapp deploy: cache SCM URL and headers within a …#33560

Open
naveedaz wants to merge 1 commit into
Azure:devfrom
naveedaz:fix/appservice-cache-scm-headers-onedeploy
Open

{App Service} az webapp deploy: cache SCM URL and headers within a …#33560
naveedaz wants to merge 1 commit into
Azure:devfrom
naveedaz:fix/appservice-cache-scm-headers-onedeploy

Conversation

@naveedaz

@naveedaz naveedaz commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Related command

az webapp deploy, az functionapp deploy

Description

az webapp deploy and az functionapp deploy issue ~12 redundant ARM calls per invocation. Most duplication comes from helpers that independently fetch the same Site model, SCM URL, publishing credentials, and is_flex status:

  • _get_scm_url fetches GET /sites to resolve the SCM hostname — called twice (publish URL + status URL).
  • get_scm_site_headers runs is_flex_functionapp + basic_auth_supported + _get_site_credential — called twice (publish POST + status poll), wasting 3+ ARM calls each time.

This PR hoists per-invocation state onto OneDeployParams:

  1. Eager Site fetch — fetch the Site model once, cache on _cached_site. Derive SCM URL (from host_name_ssl_states), is_linux (from reserved), is_flex (from sku), and visit URL (from enabled_host_names) — zero additional ARM calls.
  2. SCM headers cache — cache get_scm_site_headers result on _cached_scm_headers. Reused by status poller, Kudu warmup, and _get_latest_deployment_id. On HTTP 401 the cache is dropped and headers are refetched once.
  3. Security_cached_scm_headers is cleared in a finally block so basic-auth credentials cannot outlive the invocation.
  4. Case-insensitive auth keyurllib3.util.make_headers(basic_auth=...) returns lowercase 'authorization'; AAD uses 'Authorization'. Cache population handles both via case-insensitive key matching.

ARM call reduction (verified via E2E)

Scenario Before After
Linux webapp (AAD) ~12 3 (GET /sites, GET basicPub/scm, GET instances)
Consumption function app ~8 2 (GET /sites, GET basicPub/scm)
Flex function app ~6 1 (GET /sites)

Testing Guide

Deploy with --debug and count Request URL:.*management.azure.com lines (excluding deploymentStatus polling):

az webapp deploy -g <rg> -n <app> --src-path <zip> --type zip --debug

Unit tests: 160 tests covering cache lifecycle, SCM URL derivation from host_name_ssl_states, slot awareness, is_flex hint from cached SKU, header caching, and cache cleanup on success/exception.

History Notes

[App Service] az webapp deploy/az functionapp deploy: Reduce per-deploy ARM calls from ~12 to ~3 by caching the Site model, SCM URL, and SCM authentication headers for the lifetime of a single deploy invocation

@azure-client-tools-bot-prd

azure-client-tools-bot-prd Bot commented Jun 16, 2026

Copy link
Copy Markdown
️✔️AzureCLI-FullTest
️✔️acr
️✔️latest
️✔️3.12
️✔️3.14
️✔️acs
️✔️latest
️✔️3.12
️✔️3.14
️✔️advisor
️✔️latest
️✔️3.12
️✔️3.14
️✔️ams
️✔️latest
️✔️3.12
️✔️3.14
️✔️apim
️✔️latest
️✔️3.12
️✔️3.14
️✔️appconfig
️✔️latest
️✔️3.12
️✔️3.14
️✔️appservice
️✔️latest
️✔️3.12
️✔️3.14
️✔️aro
️✔️latest
️✔️3.12
️✔️3.14
️✔️backup
️✔️latest
️✔️3.12
️✔️3.14
️✔️batch
️✔️latest
️✔️3.12
️✔️3.14
️✔️batchai
️✔️latest
️✔️3.12
️✔️3.14
️✔️billing
️✔️latest
️✔️3.12
️✔️3.14
️✔️botservice
️✔️latest
️✔️3.12
️✔️3.14
️✔️cdn
️✔️latest
️✔️3.12
️✔️3.14
️✔️cloud
️✔️latest
️✔️3.12
️✔️3.14
️✔️cognitiveservices
️✔️latest
️✔️3.12
️✔️3.14
️✔️compute_recommender
️✔️latest
️✔️3.12
️✔️3.14
️✔️computefleet
️✔️latest
️✔️3.12
️✔️3.14
️✔️config
️✔️latest
️✔️3.12
️✔️3.14
️✔️configure
️✔️latest
️✔️3.12
️✔️3.14
️✔️consumption
️✔️latest
️✔️3.12
️✔️3.14
️✔️container
️✔️latest
️✔️3.12
️✔️3.14
️✔️containerapp
️✔️latest
️✔️3.12
️✔️3.14
️✔️core
️✔️latest
️✔️3.12
️✔️3.14
️✔️cosmosdb
️✔️latest
️✔️3.12
️✔️3.14
️✔️databoxedge
️✔️latest
️✔️3.12
️✔️3.14
️✔️dls
️✔️latest
️✔️3.12
️✔️3.14
️✔️dms
️✔️latest
️✔️3.12
️✔️3.14
️✔️eventgrid
️✔️latest
️✔️3.12
️✔️3.14
️✔️eventhubs
️✔️latest
️✔️3.12
️✔️3.14
️✔️feedback
️✔️latest
️✔️3.12
️✔️3.14
️✔️find
️✔️latest
️✔️3.12
️✔️3.14
️✔️hdinsight
️✔️latest
️✔️3.12
️✔️3.14
️✔️identity
️✔️latest
️✔️3.12
️✔️3.14
️✔️iot
️✔️latest
️✔️3.12
️✔️3.14
️✔️keyvault
️✔️latest
️✔️3.12
️✔️3.14
️✔️lab
️✔️latest
️✔️3.12
️✔️3.14
️✔️managedservices
️✔️latest
️✔️3.12
️✔️3.14
️✔️maps
️✔️latest
️✔️3.12
️✔️3.14
️✔️marketplaceordering
️✔️latest
️✔️3.12
️✔️3.14
️✔️monitor
️✔️latest
️✔️3.12
️✔️3.14
️✔️mysql
️✔️latest
️✔️3.12
️✔️3.14
️✔️netappfiles
️✔️latest
️✔️3.12
️✔️3.14
️✔️network
️✔️latest
️✔️3.12
️✔️3.14
️✔️policyinsights
️✔️latest
️✔️3.12
️✔️3.14
️✔️postgresql
️✔️latest
️✔️3.12
️✔️3.14
️✔️privatedns
️✔️latest
️✔️3.12
️✔️3.14
️✔️profile
️✔️latest
️✔️3.12
️✔️3.14
️✔️rdbms
️✔️latest
️✔️3.12
️✔️3.14
️✔️redis
️✔️latest
️✔️3.12
️✔️3.14
️✔️relay
️✔️latest
️✔️3.12
️✔️3.14
️✔️resource
️✔️latest
️✔️3.12
️✔️3.14
️✔️role
️✔️latest
️✔️3.12
️✔️3.14
️✔️search
️✔️latest
️✔️3.12
️✔️3.14
️✔️security
️✔️latest
️✔️3.12
️✔️3.14
️✔️servicebus
️✔️latest
️✔️3.12
️✔️3.14
️✔️serviceconnector
️✔️latest
️✔️3.12
️✔️3.14
️✔️servicefabric
️✔️latest
️✔️3.12
️✔️3.14
️✔️signalr
️✔️latest
️✔️3.12
️✔️3.14
️✔️sql
️✔️latest
️✔️3.12
️✔️3.14
️✔️sqlvm
️✔️latest
️✔️3.12
️✔️3.14
️✔️storage
️✔️latest
️✔️3.12
️✔️3.14
️✔️synapse
️✔️latest
️✔️3.12
️✔️3.14
️✔️telemetry
️✔️latest
️✔️3.12
️✔️3.14
️✔️util
️✔️latest
️✔️3.12
️✔️3.14
️✔️vm
️✔️latest
️✔️3.12
️✔️3.14

@azure-client-tools-bot-prd

azure-client-tools-bot-prd Bot commented Jun 16, 2026

Copy link
Copy Markdown
❌AzureCLI-BreakingChangeTest
❌acs
rule cmd_name rule_message suggest_message
1002 - CmdRemove aks nodepool get-rollback-versions cmd aks nodepool get-rollback-versions removed please confirm cmd aks nodepool get-rollback-versions removed
1002 - CmdRemove aks nodepool rollback cmd aks nodepool rollback removed please confirm cmd aks nodepool rollback removed

Please submit your Breaking Change Pre-announcement ASAP if you haven't already. Please note:

  • Breaking changes can only be merged during the designated breaking change window
  • A pre-announcement must be released at least one month in advance

For more details on how to introduce breaking changes, refer to the documentation: azure-cli/doc/how_to_introduce_breaking_changes.md

@yonzhan

yonzhan commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

App Service

@naveedaz naveedaz force-pushed the fix/appservice-cache-scm-headers-onedeploy branch 2 times, most recently from ff243b4 to bf34e57 Compare June 17, 2026 00:28
…single deploy invocation

`az webapp deploy` currently issues ~12 ARM calls per invocation. Most of
the duplication comes from two helpers that are called twice each within a
single deploy:

* `_get_scm_url` is called from `_build_onedeploy_scm_url` (publish URL)
  and `_get_onedeploy_status_url` (status URL). The SCM hostname does not
  change between the two — 1 ARM call (`GET /sites`) is wasted.
* `get_scm_site_headers` is called from `_get_ondeploy_headers` (publish
  POST) and again ~20–60 s later from `_check_zip_deployment_status`
  (status poll). Each invocation runs `is_flex_functionapp` +
  `basic_auth_supported` + `_get_site_credential` — 3 wasted ARM calls.

Hoist both results onto `OneDeployParams` for the lifetime of one deploy,
reuse them on the status leg, and clear them in a `finally` block so a
basic-auth credential cannot outlive the invocation (and cannot be observed
by outer exception handlers or telemetry). On a HTTP 401 from the poll we
drop the cache and refetch once to handle credential rotation.

Net effect per invocation: 12 → 7 ARM calls (–42%), and the
`_get_site_credential` exposure (the call that has been observed to surface
sporadic `ConnectionResetError(10054)`) drops from 2 to 1.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@naveedaz naveedaz force-pushed the fix/appservice-cache-scm-headers-onedeploy branch from bf34e57 to c79a930 Compare June 17, 2026 00:29
@naveedaz naveedaz marked this pull request as ready for review June 17, 2026 01:15
Copilot AI review requested due to automatic review settings June 17, 2026 01:15

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

Note

Copilot was unable to run its full agentic suite in this review.

This PR introduces per-invocation caching for OneDeploy to reduce redundant ARM calls during az webapp deploy / az functionapp deploy, while adding targeted unit tests and documenting the change.

Changes:

  • Cache the Site model, derived SCM URL, and stable SCM auth headers on OneDeployParams for the duration of a deploy invocation.
  • Thread cached parameters through status polling helpers to reuse headers/site and refresh credentials on 401.
  • Add comprehensive mock-based tests and update release notes.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
src/azure-cli/azure/cli/command_modules/appservice/custom.py Implements Site/SCM URL/SCM header caching and updates OneDeploy/status polling flow to reuse cached data.
src/azure-cli/azure/cli/command_modules/appservice/tests/latest/test_webapp_commands_thru_mock.py Adds unit tests validating cache behavior, 401 refresh, and non-leakage of credentials.
src/azure-cli/HISTORY.rst Documents the reduced ARM-call behavior for deploy commands.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +11460 to +11462
headers = get_scm_site_headers(
params.cmd.cli_ctx, params.webapp_name, params.resource_group_name,
is_flex_hint=_known_is_flex_hint(params))
Comment on lines +11026 to +11030
# Eagerly fetch (and cache) the Site so downstream helpers
# (_get_or_fetch_scm_url, _get_visit_url, _get_or_fetch_is_linux_webapp)
# can derive answers from the cached model without issuing additional
# GET /sites calls. Also derive the is_flex hint here so
# get_scm_site_headers can skip the redundant is_flex_functionapp call.
Comment on lines +9763 to +9765
if deploy_params is not None and deploy_params._cached_scm_headers is not None: # pylint: disable=protected-access
headers = dict(deploy_params._cached_scm_headers) # pylint: disable=protected-access
headers['x-ms-client-request-id'] = cmd.cli_ctx.data['headers']['x-ms-client-request-id']
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants