Azure Function App Circuit Breaker Pattern: Managing Function Triggers at Scale

In todayโ€™s cloud-native world, building resilient systems is more important than ever. As teams adopt microservices and rely on various downstream dependencies, it becomes crucial to handle failures gracefully. One common challenge when working with Azure Functions is how to temporarily pause message processing. In this post, we’ll explore how to implement a circuit breaker pattern that allows you to programmatically disable and re-enable function triggers, helping your system recover smoothly without losing data or overwhelming dependent services.

If you’re using Azure Functions at scale, you’ve likely encountered scenarios where you need to temporarily pause processing:

  • A critical downstream service is experiencing an outage
  • You’ve hit API rate limits with an external service
  • You’re performing maintenance on dependent systems
  • You need to recover from an incident without processing new events

Manually disabling function triggers through the Azure Portal is cumbersome and doesn’t scale well. Automating this process provides more reliability and helps prevent cascading failures across your architecture.

The Solution

The solution is based on an Azure Function App called called FuncTriggerManager which provides a circuit breaker pattern implementation for other Azure Function Apps. It allows you to programmatically enable or disable function triggers.

Letโ€™s walk through the flow at a high level:

  1. Function Triggered by Message
    An Azure Function is triggered by a message from a Service Bus queue or topic.
  2. Processing and API Call
    The function processes the message and attempts to forward it to a downstream API.
  3. Failure Detected
    If the API responds with an HTTP 503 (Service Unavailable), the function logs the error and sends a control message to an Azure Storage Queue.
  4. Trigger Manager Disables Function
    A separate Function App (FuncTriggerManager) listens to this queue, disables the affected Function App, and places another message on the queue with a scheduled delay.
  5. Function Re-enabled
    After the delay, the manager function re-enables the original Function App, allowing message processing to resume once the downstream service is likely to have recovered.

Key Features

  • Queue-based control: Send simple messages to enable/disable specific functions
  • Automatic re-enablement: Set a time period after which functions automatically resume
  • Minimal permissions: Uses managed identity with least privilege access
  • Simple integration: Minimal code changes needed in your existing functions

How it works

The solution consists of an Azure Function with a queue trigger that:

  1. Monitors a designated storage queue for control messages
  2. Parses instructions about which function to enable/disable
  3. Uses Azure Resource Manager APIs to modify the function’s settings
  4. If configured, automatically re-enables functions after a specified period

Here’s what the control message looks like:

{
  "FunctionAppName": "YourFunctionAppName",
  "FunctionName": "SpecificFunctionName",
  "RessourceGroupName": "YourResourceGroupName", 
  "DisableFunction": true,
  "DisablePeriodMinutes": 30
}

When this message is processed, the specified function will be disabled for 30 minutes, then automatically re-enabled. If you set DisablePeriodMinutes to 0 or omit it, the function will remain disabled until explicitly enabled.

Full source code of the solution can be found here https://github.com/connectedcircuits/funcappshortcct

Implementation Details

Under the hood, FuncTriggerManager uses the Azure Management APIs to modify a special application setting called AzureWebJobs.<FunctionName>.Disabled that controls whether a specific function trigger is enabled. This is the same mechanism used by the Azure Portal when you manually disable a function.

The FuncTriggerManager service authenticates using its managed identity with the following permissions applied to the Function App you wish to control.

  • Reader access to the resource group of function apps to control
  • Website Contributor permissions on target function apps to control

Testing with a Sample Function App

I have included a sample Function App so you can follow how to send a control message onto the storage queue. This sample Function App is triggered when a message is placed onto a Service Bus queue. It then sends the message to a HTTP endpoint which represents an API. If it returns a status code of 5xx a control message is placed onto the Storage Account queue to disable its trigger.

The test function simulates a real-world scenario where you might need to temporarily disable message processing triggered messages from a Service Bus queue.

The source code for sample simulator can be found here – https://github.com/connectedcircuits/FuncSbProxy-funcappshortcct-

Getting Started

To implement this pattern in your environment:

  1. Deploy the FuncTriggerManager function app with managed identity
  2. Set up the required app settings:
    • StorageConnection: Connection string to your Azure Storage
    • QueueName: Name of the queue to monitor
    • AzureSubscriptionId: Your Azure subscription ID
  3. Develop your Function App service and copy the DisableFuncMessenger.cs (as in the sample FuncSbProxy)
  4. Setup the required app setting your Function App service
    • StorageConnection: Connection string to your Azure Storage
    • QueueName: Name of the queue to monitor
    • ResourceGroupName: Name of the Azure Resource where this function app will be deployed to.
    • DisableFuncPeriodMin: Time in minutes you want disable the trigger for.

Real-World Use Cases

Here are some scenarios where I’ve found this pattern particularly useful:

Scenario 1: Downstream Service Outage

When an external API reports a 503 Service Unavailable error, your error handling code can place a message in the circuit breaker queue to disable the corresponding function until the service recovers.

Scenario 2: Rate Limit Protection

If your function processes data that interacts with rate-limited APIs, you can temporarily disable processing when approaching limits and schedule re-enablement when your quota resets.

Conclusion

The circuit breaker pattern is essential for building resilient systems, and having an automated way to implement it for Azure Functions has been invaluable in our production environments. FuncTriggerManager provides a simple yet powerful approach to managing function trigger states programmatically.

By incorporating this pattern into your Azure architecture, you can improve resilience, reduce cascading failures, and gain more control over your serverless workflows during incidents and maintenance windows.


Note: Remember to secure your circuit breaker queue appropriately as it provides control over your function apps’ operation.

Enjoy…

Always Linter your API Definitions

An API definition may be thought of as an electronic equivalent of a receptionist for an organisation. A receptionist is normally the first person they see when visiting an organisation and their duties may include answering enquires about products and services.

This is similar to an API definition, when someone wants to do business electronically, they would use the API definition to obtain information about the available services and operations.

My thoughts are, API’s should be built customer first and developer second. Meaning an API needs to be treated as a product and to make it appealing to a consumer, it needs to be designed as intuitive and usable with very little effort.

Having standardised API definition documents across all your API’s, allows a consumer to easily navigate around your API’s as they will all have a consistent look and feel about them. This specially holds true when there are multiple teams developing Microservices for your organisation. You don’t want your consumers think they are dealing with several different organisations because they all look and behave differently. Also, when generating the client object models from several different API definitions from the same organisation, you want the property names to all follow the same naming conventions.

To ensure uniformity across all API schema definitions, a linter tool should be implemented. One such open-source tool is Spectral https://github.com/stoplightio/spectral from Stoplight, however there are many other similar products available.

Ideally the validation should be added as a task to your CI/CD pipelines when committing the changes to your API definition repository.

Using Spectral in MS DevOps API Projects

Spectral provides the capability to develop custom rules as a yaml or json file. I typically create a separate DevOps project to store these rules inside a repository which may be shared across other API projects.

Below is how I have setup the repositories section in the pipeline to include the linter rules and the API definition.

image

After downloading the Spectral npm package in the pipeline, I then run the CLI command to start the linter on the schema specification document which is normally stored in a folder called ‘specification’ in the corresponding API repository.

clip_image001

An example of the pipeline job can be seen below. Here the job failed due to some rule violations.

clip_image002

The build pipeline and sample rules can be found here https://github.com/connectedcircuits/devops-api-linter

Hope this article now persuades you to start using Linter across all your API definitions.

Enjoyโ€ฆ

Connecting an Azure WebApp to a SQL Server VM inside a VNet

This article is about connecting an Azure WebApp to a SQL Server VM which is hosted inside an Azure Virtual Network. Typically a SQL Server VM would be hosted inside an Azure Virtual Network (VNet)  to isolate it from the internet by blocking all inbound and outbound internet traffic using a Network Security Group (NSG). In this scenario, connectivity  to the SQL Database is achieved by using the new VNet Integration feature found on the App Service component. Using this feature removes the requirement of an App Service Environment (ASE) for the WebApp thus reducing overall hosting costs.

Using VNet integration provides private outbound access from your App Service to resources in your VNet using the RFC1918 internal IP address allocation range (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) by default.

 

Scenario

A web application is hosted in a WebApp which requires a connection to the SQL Database hosted inside a VNet.

The network topology of this scenario is shown below which uses the Regional VNet Integration option where both the WebApp and SQL VM are in the same region. Here we have a VNet called Backend which has two subnets, one for the VNet Integration used for delegating called IntegDeleg and the other to host the SQL Server VM called DataStore.

 

image

 

Configuration Walkthrough

The following are the sequence of steps used to setup VNet Integration between a Web App and SQL Server with the assumption the SQL Server VM is already hosted inside a VNet.

1. Adding a VNet subnet

2. Provisioning  an AppSvc Plan

3. Provisioning  a WebApp

4. Setting up the VNet Integration

5. Validating SQL Server Security Settings

6. Testing connectivity to the SQL Server

7. Updating the Web App SQL Connection String

 

1. Adding a VNet Subnet

A dedicated subnet used by the VNet Integration feature is required to be added to the existing VNet hosting the SQL Server VM. The IP range should match the maximum number of AppSvc plan instances when fully scaled out as each instance would require a IP address. For this scenario I will be using a /27  prefix giving a total range of 32 address, however  5 address are used internally by Azure leaving 27 usable addresses for each plan instance.

 

image

 

2. Provisioning App Svc Plan

To use VNet Integration, you will need to provision an App Service plan using newer V2 scale units. Note if you are currently using V1 App Services, you will need to provision a new plan using V2 and migrate you apps to this new plan.

To confirm if you have selected the newer V2 App Services, the Premium plans should be shown as P1V2, P2V2 and P3V2. Here I will be using a Standard Plan S1 for this scenario highlighted below.

image

 

3. Provisioning Web App

Create a new Web App and ensure it is in the same region as the VNet. Also ensure you have selected the  App Service Plan you created above.

image

 

4. Enable VNet Integration

Under the Web App that was provisioned above, click on the Networking menu item to view the networking options and then click on โ€œClick here to configureโ€ under the VNet Integration heading.

image

 

Once the VNet Configuration form opens, click on the โ€œAdd VNetโ€ to open the Network Feature Status blade. Select the VNet that hosts the SQL Server and then the Subnet that was created earlier for the VNet Integration. Then press OK to save the changes.

 image

 

After you hit OK, the VNet Integration should be connected and ready for testing the connectivity. Remember the VNet Integration will route all outbound RFC1918 traffic from the WebApp into your VNet.

 

image

 

5. Validating SQL Server Security Settings

To reduce the surface area of attack, ensure the SQL Server can only accept connections within the VNet. This is done by setting the โ€œSQL connectivityโ€ option to Private (within Virtual Network) under the Security menu of the SQL Virtual Machine.

 

image

 

Also check the NSG attached to the SQL Server VM to ensure there is a rule to disable all outbound internet traffic. If there is a inbound rule called default-allow-sql as highlighted below, it is advisable to delete this rule if not required. This inbound rule default-allow-sql is normally created when the security on the SQL Server VM allows SQL connectivity via Public (Internet) connections.

 

image

 

6. Testing connectivity

To check connectivity between the Web App and the SQL server, we can use the  tcpping command from a console window. Go to the Web App that was created previously and click on the Console menu item to open a console window similar to below.

image

In the console window type the command tcpping <sql vm private ip address>:1433. All going well you should get a reply similar to that below where 10.0.2.4 was the private IP address of my SQL Server VM using the default port 1433.

image

 

7. Updating the Web App SQL Connection String

Once the connectivity has been verified, the next step is to update the connection string on the Web App to use the private IP address of the SQL Server VM. Typically the connection string should look something like this:- Server=10.0.2.4;Database=coreDb;User Id=myusername;Password=mypassword;MultipleActiveResultSets=true

After the connection string has been updated to use the private IP address, you should be able to test your application. Here I am just adding some new tasks in the TodoList web application and confirming the records are written to the database.

 image

 

Conclusion

VNet Integration provides an easy and cost effective solution to access databases hosted within a VNet without resorting to a dedicated  ASE. Also using rules on the NSG applied to the SQL Server VM provides the capability to block all internet traffic and allow only RFC1918 internal addresses to have access.

More information about VNet Integration can be found on the MS docs site https://docs.microsoft.com/en-us/azure/app-service/web-sites-integrate-with-vnet.

Enjoyโ€ฆ