App Service plans that never passed 40% CPU in 30 days and can drop one size
What does ZopNight detect here?
Azure App Service plans on dedicated tiers bill for every VM instance at the plan's size. ZopNight flags a plan whose `CpuPercentage` peak stayed under 40% for 30 days, with memory averaging under 50%, and prices a one-step move within the same tier, such as `P2V3` to `P1V3`, from real Windows or Linux rates.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-1310 |
| Category | rightsizing |
| Severity | medium |
| Metric | CpuPercentage |
| Threshold | 30-day peak below 40%, memory below 50% |
| Evaluation window | 30d |
| Source | ZopNight |
| Permissions used | Microsoft.Web/serverfarms/Read · Microsoft.Insights/Metrics/Read |
Where it applies
Every instance of an oversized plan is paid for
The plan, not the app, is the billing unit. Microsoft’s hosting plans overview explains that on the dedicated tiers (Basic, Standard and the Premium families) the plan defines how many VM instances the apps run on, and each VM instance is charged. All apps in the plan share those instances and scale together. A plan chosen for a launch and never revisited keeps paying for headroom on every instance.
Reading a plan’s peak CPU and memory
az appservice plan list \ --query "[].{name:name, group:resourceGroup, sku:sku.name, workers:sku.capacity, apps:numberOfSites}" -o table
az monitor metrics list \ --resource /subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Web/serverfarms/<plan> \ --metric CpuPercentage MemoryPercentage --aggregation Maximum Average --interval PT1H --offset 30dWhat has to be true before a smaller size is suggested
CpuPercentagedata covers at least the full 30 days.- The highest CPU reading in that window is below 40%, so even the busiest hour would fit a smaller instance.
- If memory data is present,
MemoryPercentageaverages below 50%, which rules out memory-bound plans. - A smaller size exists in the same tier family. The steps are B3 to B2 to B1, S3 to S2 to S1, and the same within PremiumV2, PremiumV3, PremiumMV3 and IsolatedV2.
- Real hourly rates exist for both sizes, using the plan’s operating system, and the plan has a price.
Plans that are not touched
A plan already on the smallest size of its family (B1, S1, P1V2, P0V3 and so on) gets no finding; the rule only moves within a family. Jumping to a cheaper family can remove features such as staging slots or autoscaling, which Microsoft’s scale-up guide ties to the pricing tier. Less than 30 days of CPU data, or any missing rate, also means no finding. A plan with no apps at all is a different case, handled by Idle Azure App Service Plan.
The saving from one size down
saving = (current size hourly rate - smaller size hourly rate) applied to the plan's monthly costcost after fix = current cost - savingThe instance count stays the same; only the size of each instance changes.
Scaling the plan down
- Review CPU and memory for the whole plan and for each app on it over the last 30 days.
- Change the size, in the portal under Scale up, or with
az appservice plan update --resource-group <rg> --name <plan> --sku <smaller-size>. - Watch response times and CPU for a few days after the change, and scale back up if the peak crosses your comfort line.