Why Azure Container Apps drops requests during a spike
Azure Container Apps scales containers by events and metrics, but during a sharp traffic spike the application still starts returning 5xx.
The issue is not a lack of resources, but the delay in the control loop: the decision to add replicas is made more slowly than the load grows.
The autoscaling rule relies on an averaged metric over an observation window — the counter needs to accumulate statistics before it triggers.
While the window fills, the number of concurrent requests per replica has already doubled, the ingress queue grows, and new instances have not yet been created. Container scaling proceeds in steps, while traffic arrives in a surge.
Then cold start comes into play: a replica needs to pull the image, start the runtime, warm up, and pass readiness checks.
In the first seconds it either does not accept traffic or accepts it while not warmed up — response time in this segment is higher than that of already running instances. If readiness checks are configured formally, the flow goes to a process that is not yet holding connections.
Thus, failures during a spike consist of two waves: first, ingress flow exceeds current capacity before autoscaling triggers; then some requests land on unready replicas.
In metrics, this shows up as 503 at ingress, growth in the 95th and 99th percentile response time, and connection drops for some clients.
We break down how this is closed: proactive autoscaling rules for peak load, warm-up and gradual traffic delivery, so scaling keeps up before the request queue turns into failures.
What autoscaling and canary release provide
Canary release keeps two revisions at once: 5-10% of traffic goes to the new one, the rest is served by the previous one.
The error rate and response time of the new revision are compared with the baseline in real time — if a threshold is exceeded, traffic returns to the proven revision within seconds. There is no service downtime: the user sees neither a restart nor connection drops.
Event-driven scaling changes the reaction profile to load.
Replicas are added not based on CPU utilization, but based on queue length and the number of unclosed messages, so a nighttime burst is handled tens of seconds earlier than a hardware metric threshold would have triggered.
In Azure Container Apps, scaling rules and traffic splitting between revisions are described declaratively, so behavior under load is reproducible on any environment rather than configured anew.
This leads to classes of incidents that stop reaching the user:
- degradation after release: rollback in seconds, without manual intervention by the on-call engineer;
- failure of one zone: replicas come up in the remaining ones, recovery time is a few seconds;
- nighttime queue: capacity grows with it and goes down the same way when the flow subsides.
The result is measurable: recovery time is reduced from minutes to seconds, the failure rate is limited by the size of the canary traffic share, and capacity follows load without overpaying for idle time.
Scaling modes and version release strategies
In Azure Container Apps, scaling and version release rely on one mechanism — immutable application revisions. Each revision gets its own traffic share, so rolling out a new build and rolling back are performed by switching weights, without rebuilding or downtime.
Capacity is set by rules: by CPU and memory utilization, by queue length, by schedule — up to scaling to zero.
| Option | When it fits | Limitations |
|---|---|---|
| Fixed number of replicas | steady load, internal services | does not survive a spike, resources sit idle during off-peak |
| Metric-based rules | variable traffic, queue draining | delayed reaction, sensitivity to threshold, cold start |
| Schedule | known windows: business hours, batch jobs | does not cover an unplanned spike outside the window |
| Traffic-share release | testing a version on a subset of users | both versions run simultaneously: service contracts and data schema must be compatible |
| Blue-green release | critical service, instant rollback needed | double resource reserve during switchover |
Common limitation: data compatibility
The common limitation across all strategies is state. While traffic is split between versions, schema changes must be backward compatible: first add fields and read both formats, remove the old ones only after full switchover. Otherwise, rollback will return code that no longer understands the data.
How we implement autoscaling: work stages
The order of work is built from measured load to rules, not the other way around: first we capture the demand profile in Azure Container Apps, then fix the scaling scheme, and only then enable changes in the production loop. The discrepancy between test and production service behavior is a common source of false triggers.
- Load assessment. We capture metrics over several weeks: request intensity, processing duration, queue depth, resource consumption at peaks. Based on them, we choose a trigger that reflects real demand rather than an indirect sign.
- Scaling scheme. We separate frontend, API, and background workers into independently scalable groups, set minimum and maximum replicas, and separate environments so development does not compete with production for capacity.
- Rule configuration. We describe KEDA triggers — queue, event stream, schedule — and select cooldown windows with an increment step so replicas do not thrash on short bursts. We store rules as code and put them through review.
- Canary deploy. We roll out the version to a share of traffic, compare the error rate and response time with the baseline, and configure automatic rollback by threshold.
- Acceptance checks. We run the load profile from the first step with stepwise spikes and failure of an external dependency: measure time to reach peak, replica ceiling, and recovery time.
- Handover to operations. We hand over configuration in repositories, dashboards for replicas and triggers, alerts for hitting the ceiling and for failures, and an on-call procedure with typical scenarios.
Configurations, diagrams, and procedures after implementation
After the service is rolled out to production, the team is left not only with a working loop but also with a set of artifacts by which it can be changed without us.
Everything is stored in the customer's repository along with the edit history: configuration changes go through review and reach the environment the same way as code, so in Azure Container Apps there are no settings made "by hand through the console." Below is what exactly we hand over.
- Scaling configuration — rules and replica range for each service, metric trigger thresholds, idle behavior, and warm-up time before accepting load.
- Service diagram — connections between components, entry points, queues, and external dependencies, with an explicit boundary of responsibility between the application and the platform.
- Access rules — roles, service identities, network restrictions, and the procedure for granting rights to a new component or contractor.
- Release procedure — the canary release process: traffic share to the new revision, promotion criteria metrics, and automatic rollback conditions.
- Rollback instructions — step-by-step return to the previous revision, including data schema compatibility and post-rollback checks.
- Observability map — which metrics, logs, and alerts are set up, what thresholds they are configured for, and who receives a notification when they trigger.
- Environment guide — how environments differ, where secrets and variables are stored, and how to add a new environment without editing templates.
Case study: peak load without manual intervention
A service for processing requests for corporate clients held a peak at the end of the business day and at the beginning of the reporting period: in an hour it received as many requests as during the rest of the day.
Scaling was tied to CPU utilization, and it grew only after the processing queue overflowed. At peak, the share of failed requests reached 8%, the 95th percentile response stretched to several seconds, and the on-call engineer manually added replicas three to four times a day.
The application was moved to Azure Container Apps and scaling was switched to external metrics — queue length and number of concurrent requests instead of CPU utilization.
The scale-up threshold was set with headroom, and replica scale-down with a delay so a short dip would not remove already warmed-up instances.
Before enabling it in production, we ran load tests based on a snapshot of the real peak: held the extreme profile and watched how long it took to reach the required number of replicas and how the queue behaved during a sharp drop.
Based on the results, we raised the minimum number of replicas and configured warm-up so the first wave of requests would not hit a cold start.
After the migration, on-call became planned — once a week instead of three or four calls a day. The share of failed requests dropped from 8% to 0.4%, the 95th percentile response was reduced by three times, and the peak is served without engineer involvement. Rollout to a traffic share was left enabled: rollback to the previous version takes minutes.
How autoscaling in Azure differs from manual
Manual scaling keeps a specified number of replicas: the platform does not look at load until an engineer changes the value themselves.
On a steady flow, this is predictable, but a burst — queue growth, delays, failures — is only handled by the on-call engineer, and during quiet hours you pay for idle resources.
Schedule-based scaling removes part of the manual work: a rule sets how many replicas to keep during business hours and how many at night. This works with a repeating load profile and breaks down for one-off campaigns.
| Option | When it fits | Limitations |
|---|---|---|
| Manual | Steady flow, debugging, infrequent releases | Reaction only from the on-call engineer |
| Schedule-based | Recurring daily and weekly peaks | Does not see unplanned growth |
| Event-driven | Queues, request streams, batch jobs | Requires the right threshold and stabilization window |
| Combined | Predictable baseline plus bursts | Harder to configure, requires load testing |
Event-driven scaling relies on a metric: queue length, number of concurrent requests, CPU utilization.
The scaling threshold and stabilization window determine at what value a replica is added and how long it lives after a decline — a narrow window causes "flapping," while a wide one leaves excess capacity.
A combined scheme in Azure Container Apps covers both scenarios: the schedule brings the baseline level up to the morning peak, and the event-driven trigger adds replicas for actual load.
We first capture the load profile, then select thresholds and confirm them with a load test — otherwise the rule looks like it works but does not trigger where needed.
Technical questions asked before starting
Before starting, engineering teams usually ask the same questions: what happens to active connections at release time, will the application have to be rewritten, where is the upper scaling limit, and how the system behaves when the event source is unavailable. Below are short answers without marketing, exactly as we discuss them in a technical session.
What happens to active connections when a new version is released?
The platform brings up a new revision alongside the old one and shifts part of the traffic to it. The old one is not shut down immediately, but after processing of active requests and connections completes — there are no client-side drops.
If checks fail, the traffic weight automatically returns to the previous revision: automatic rollback is configured in advance rather than enabled manually at the moment of an incident.
Does the application need to be rewritten?
In most cases, no. The application is built into the same container as before, and declarative rules are added on top: what event to scale by, how many revisions to keep, how to distribute traffic.
Targeted changes are needed only if the service manages connections to the event source itself or keeps state in the process memory.
Where is the upper scaling limit?
It is set explicitly: minimum and maximum number of replicas plus a metric rule. This is protection against an avalanche — during a burst, load grows predictably up to the set ceiling, rather than until quota exhaustion.
We select the boundaries based on the load profile: how many events arrive at peak, how quickly one is processed, and how much headroom is needed for warm-up.
What should be done if the event source is unavailable?
We separate two cases — event source unavailability and queue lag. We set thresholds on queue length, not only on the events themselves, so scaling reacts to accumulation.
Replica behavior at zero load is also configurable: scale to zero or maintain a minimum if the service needs warm-up.
Let's discuss the autoscaling and version release task
To come back with an estimate and plan rather than general considerations, we need a minimum of input data from the customer.
Below is what we ask in the first conversation; usually half an hour of discussion and access to the repository with manifests and platform configuration, including Azure Container Apps, is enough.
- Load profile: daily and weekly schedule, peak windows, share of background and periodic jobs, distribution of requests by operation.
- Service diagram: which components are stateless, which hold state themselves, who communicates synchronously, and who does so through queues and events.
- Current scaling rules and bottlenecks: how the system behaves during a burst, how long it takes to start a new instance, and what hits platform limits.
- Version release requirements: traffic share for the canary variant, automatic rollback conditions, acceptable window of partial degradation.
- Access and constraints: environments, private networks, roles, security policies, and the change procedure in production.
- Acceptance of the result: which metrics we consider target and in which scenarios we test — sharp burst, instance failure, rollback to the previous release.
Describe the task in free form — we will come back with an estimate, work plan, and breakdown into stages. On a call, we will show how the solution maps to your service diagram and agree on the acceptance procedure for the result in advance.







