Azure Functions’ traffic splitting isn’t about sending a percentage of requests to different function versions directly; it’s about routing traffic to different deployment slots, each of which can host a specific version of your function app.
Let’s see this in action. Imagine you have a function app named my-function-app in Azure. You deploy your initial stable version to the production slot.
# Deploying version 1.0 to production
az functionapp deployment slot create --name my-function-app --slot production --configuration-source-settings-file prod-settings.json
az functionapp deployment source config-zip --name my-function-app --slot production --src my-function-app-v1.zip
Now, you develop version 2.0. Instead of deploying it directly to production, you create a staging slot, let’s call it staging, and deploy v2.0 there.
# Creating a staging slot
az functionapp deployment slot create --name my-function-app --slot staging
# Deploying version 2.0 to staging
az functionapp deployment source config-zip --name my-function-app --slot staging --src my-function-app-v2.zip
At this point, both production and staging are independent deployments. You can access them via their unique URLs. production is at my-function-app.azurewebsites.net, and staging is at my-function-app-staging.azurewebsites.net.
The magic happens when you want to shift traffic. Azure Functions doesn’t have a built-in percentage-based traffic shuffler between slots in the way you might imagine for, say, a load balancer. Instead, you achieve this through a mechanism called "swap."
When you’re ready to promote staging (v2.0) to be the new production, you perform a swap.
# Swapping staging into production
az functionapp deployment slot swap --name my-function-app --slot staging --target-slot production
This swap is atomic. It redirects all incoming traffic from the production URL to the staging slot’s underlying infrastructure, and simultaneously, the old production infrastructure is moved to the staging slot name. This is a zero-downtime operation.
But what if you want to send, say, 10% of traffic to v2.0 (in staging) and 90% to v1.0 (still in production, for now)? Azure Functions, by itself, doesn’t do this natively with its slots. The swap is an all-or-nothing operation.
To achieve percentage-based traffic splitting between versions, you typically need an intermediary. The most common pattern is to use Azure Application Gateway or Azure Front Door in front of your function app. These services act as your global or regional entry point.
Here’s how that would look conceptually:
- Function App with Slots: You’d still deploy your versions to different slots. Let’s say v1 is in
productionand v2 is instaging. - Application Gateway/Front Door: You configure your Application Gateway or Front Door to route traffic.
- You’d define backend pools for each slot. One pool points to the
productionslot’s IP or hostname, and another points to thestagingslot’s IP or hostname. - You then set up routing rules. For percentage-based splitting, Application Gateway (v2 SKU) and Front Door have features for this. You define rules that send a certain percentage of requests to the
productionbackend pool and the remaining percentage to thestagingbackend pool.
- You’d define backend pools for each slot. One pool points to the
For example, with Application Gateway v2, you’d configure a "weighted routing rule." You might set:
- Backend Pool A (Production Slot): Weight 90
- Backend Pool B (Staging Slot): Weight 10
This means 90% of traffic hitting the Application Gateway’s listener will be directed to the production slot, and 10% will go to the staging slot.
// Example snippet of an Application Gateway routing rule configuration
{
"name": "MyWeightedRule",
"priority": 100,
"frontendIPConfiguration": {
"id": "/subscriptions/.../resourceGroups/.../providers/Microsoft.Network/applicationGateways/.../frontendIPConfigurations/appGatewayFrontendIP"
},
"backendHttpSettings": {
"id": "/subscriptions/.../resourceGroups/.../providers/Microsoft.Network/applicationGateways/.../backendHttpSettingsCollection/default"
},
"httpListener": {
"id": "/subscriptions/.../resourceGroups/.../providers/Microsoft.Network/applicationGateways/.../httpListeners/appGatewayHttpListener"
},
"requestRoutingRules": [
{
"name": "MyWeightedRule",
"priority": 100,
"ruleType": "Basic",
"httpListener": {
"id": "/subscriptions/.../resourceGroups/.../providers/Microsoft.Network/applicationGateways/.../httpListeners/appGatewayHttpListener"
},
"backendAddressPool": {
"id": "/subscriptions/.../resourceGroups/.../providers/Microsoft.Network/applicationGateways/.../backendAddressPools/productionPool"
},
"backendHttpSettings": {
"id": "/subscriptions/.../resourceGroups/.../providers/Microsoft.Network/applicationGateways/.../backendHttpSettingsCollection/default"
},
"redirectConfiguration": null,
"rewriteRuleSet": null,
"loadDistribution" : {
"type": "Weighted",
"weight": 90,
"backendPools": [
{
"id": "/subscriptions/.../resourceGroups/.../providers/Microsoft.Network/applicationGateways/.../backendAddressPools/productionPool"
},
{
"id": "/subscriptions/.../resourceGroups/.../providers/Microsoft.Network/applicationGateways/.../backendAddressPools/stagingPool",
"weight": 10
}
]
}
}
]
}
This setup allows you to gradually roll out new versions. If the 10% of users hitting v2.0 report no issues, you can gradually increase the weight for the staging backend pool (e.g., 50/50, then 75/25) until you’re ready to perform a full swap or simply have v2.0 handle 100% of traffic.
The key takeaway is that Azure Functions deployment slots are for staging and direct swapping, not for granular traffic percentage splitting on their own. You leverage other Azure services like Application Gateway or Front Door to achieve that.
The next step is understanding how to configure health probes on Application Gateway or Front Door to ensure that traffic is only sent to healthy instances of your function app across its slots.