Adventures with Cosmos DB: Change Feed – Part 2

In Part 1 we looked at how to setup the Azure environment with a Cosmos DB and several Azure Functions, most of which, would be listening to the Cosmos DB change feed.

In Part 2 we will take a deeper dive into each Azure Function and the nuances of working with the Cosmos DB change feed.

FunctionApp1

The FunctionApp1 project has a single function, Function1, whose sole purpose is to write documents to the Cosmos DB so the other function apps can respond to.

To create some test documents, open your favorite API tool, in my case, I will be using Postman.

To get your FunctionApp1 Url, navigate to the function app in the Azure Portal, click on Function1 and then click </> Get Function URL.

Paste that into value into your API tool.

Make it a POST request, and then send the JSON body as displayed below.

Whatever you set the value of copies to will determine how many documents are created.

FunctionApp2

Now let’s look at the first function app, FunctionApp2, that handles processing the changes from the Cosmos DB change feed. In this example, we have two functions, Function1 and Function2.

Both Function1 and Function2 share the same lease container, FunctionApp2-leases.

When there are any changes to our Items collection, only one of the functions will handle the change.

We can better see what is going if we pull up the Logs for both functions, in separate browser windows.

I sent a request to create a 1,000 documents.

Only one function, in this case, Function1, handled ALL the requests.

Initially, I thought the change feed processor would balance the load across both Azure Functions, similar to what it does for a Console App written against the change feed, but my assumption was not accurate.

Why? My thought is since Azure Functions auto-scale, there is really no need for the change feed processor to spread the load across the Azure Functions.

Is there a use case for having two functions, SAME code, SAME Function App (would be in the SAME region) using the SAME lease container? There might be, but as of now, I cannot think of one.

FunctionApp3

In FunctionApp3 we have two functions, Function1 and Function2.

This time around we want BOTH functions to respond to the Cosmos DB change feed and perform independent actions while sharing the same lease container, FunctionApp3-leases.

In the Cosmos DB Trigger attributes we will set the LeaseCollectionName to FunctionApp3-leases and for each function, we will set the LeaseCollectionPrefix to the name of the function, Function1 and Function2.

When we send the request from Postman we can see that each function triggers.

Function1 Logs
Function2 Logs

If we take a peak at the lease container from the Data Explorer in the Azure Portal, in this case, FunctionApp3-leases, we can see entries for both our functions with the appropriate prefixes.

FunctionApp4

FunctionApp4 is similar to FunctionApp3, but instead of sharing a lease container, each function has it’s own lease container.

The following information is pulled from the Microsoft Docs at https://docs.microsoft.com/en-us/azure/cosmos-db/how-to-create-multiple-cosmos-db-triggers#optimizing-containers-for-multiple-triggers:

Create one leases container per Function: This approach can translate into additional costs, unless you’re using a shared throughput database. Remember, that the minimum throughput at the container level is 400 Request Units, and in the case of the leases container, it is only being used to checkpoint the progress and maintain state.

Have one lease container and share it for all your Functions: This second option makes better use of the provisioned Request Units on the container, as it enables multiple Azure Functions to share and use the same provisioned throughput.

FunctionApp5

With FunctionApp5 we have a single function, Function1.

The major difference in this example is we will deploy the function app to two Azure Function App resources, located in separate regions, East US 2 and West US 2.

However, they will still share the same lease container, as we only want one function to handle the change feed.

If we send another request in Postman we can see one of the functions being triggered, in my case, it was the function app deployed in the East US 2 region.

When I stop the function app in the East US 2 region and send my request again, the function app in the West US 2 region is triggered by the change feed.

This is a great use case if your Cosmos DB is configured for multi-master, which is a fancy way of saying Cosmos DB supports multiple write regions.

Say you have a Cosmos DB in East US 2, with an additional write region in West US 2.

If the East US 2 region goes offline, our function located in West US 2 will start processing the change feed requests now coming from the Cosmos DB in West US 2.

This is a simple way to ensure against disaster.

The only downside to this solution is the additional cost of the multiple write regions, since Azure Functions are billed based on execution, only one Azure Function will be triggered in response to the change feed.

Hopefully that made some sense, if I only confused you more, my apologies.

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *