Implementing Change Feed Notifications
Complete the full lesson to earn 25 points — 50 with Pro
Work through each section, then tap “Mark as Complete” on the last one.
✦ Skip the page breaks, the wait, and see fewer ads — read each lesson on a single page with Pro
Implementing Change Feed Notifications in Azure Cosmos DB
Introduction: The Power of Event-Driven Architectures
In the world of modern cloud applications, data is rarely static. When a user updates their profile, a sensor sends a temperature reading, or an e-commerce order is placed, that data needs to trigger a cascade of downstream actions. Traditionally, developers might have relied on polling—repeatedly asking a database "has anything changed?"—but this is inefficient, resource-heavy, and introduces unnecessary latency. Enter the Azure Cosmos DB Change Feed.
The Change Feed is a persistent log of all changes made to your Cosmos DB container, ordered by the time they were modified. It acts as a reliable, asynchronous stream of events that your applications can subscribe to. By using the Change Feed, you move from a reactive model where you constantly check for data updates to a proactive, event-driven model where your system reacts the moment a document is created, updated, or deleted.
Why does this matter? Because it decouples your services. Your primary application can focus on writing data to the database, while background processes (like indexers, analytics engines, or notification services) consume the Change Feed to perform their specific tasks. This architecture is the backbone of highly scalable systems that need to maintain synchronization across multiple microservices or storage systems without slowing down the primary data write path.
Understanding the Mechanics of the Change Feed
At its core, the Change Feed is a sorted list of documents in the order they were modified. If a document is updated multiple times, only the latest version of the document is guaranteed to appear in the feed for that specific change. It is important to note that the Change Feed does not store the history of every intermediate state; it provides a view of the current state of a document at the time of modification.
The Change Feed works by tracking the "continuation token" of the stream. This token is essentially a bookmark that tells the system where the last consumer stopped reading. When you start a process to read the Change Feed, you provide this token, and Cosmos DB serves up the changes that occurred since that specific point in time. If no token is provided, the feed can either start from the beginning of time (all existing documents) or from the current moment (only new changes).
Key Characteristics of the Change Feed
- Ordered: Changes are delivered in the order they were modified.
- Persistent: The feed is stored in the database, meaning it doesn't expire unless you define a time-to-live (TTL) policy that clears the actual data.
- Asynchronous: It does not block the primary write operations.
- At-least-once delivery: While rare, it is possible for a change to be delivered more than once, so your processing logic should be idempotent.
Callout: Change Feed vs. Polling Traditional polling requires a client to query the database repeatedly for updates, consuming Request Units (RUs) and creating unnecessary load on the database engine. The Change Feed, conversely, pushes data to the consumer. This reduces the total cost of operation and ensures that your application responds to data changes in near real-time, rather than waiting for the next polling interval to trigger.
Setting Up the Change Feed Processor Library
While you can interact with the Change Feed directly through the Cosmos DB SDKs, the recommended approach for most production scenarios is to use the Change Feed Processor (CFP) library. The CFP simplifies the complexity of distributing the workload across multiple instances and managing the state of the feed.
The processor manages the "lease" mechanism. If you have multiple instances of your application running, the CFP automatically partitions the work among them. If one instance crashes, the others detect the failure and take over the partitions that were being processed by the dead instance. This ensures high availability and resilience without you having to write complex coordination logic.
Prerequisites for Implementation
Before writing code, you need to set up two things in your Cosmos DB account:
- The Monitored Container: The container where your primary data resides.
- The Lease Container: A separate container used by the CFP to store the state (the bookmarks or continuation tokens) of the processing.
Tip: Lease Container Sizing The lease container is a small, lightweight storage area. You can usually configure it to have a very low Request Unit (RU) throughput—often just 400 RUs is sufficient—because it only performs small read/write operations to track the progress of your processor.
Step-by-Step: Implementing a Change Feed Processor
To implement a Change Feed Processor in a .NET application, follow these steps.
Step 1: Install the Required NuGet Package
You need the Microsoft.Azure.Cosmos library. You can add it via your IDE's package manager or by running the following command in your terminal:
dotnet add package Microsoft.Azure.Cosmos
Step 2: Configure the Processor
You must define the processor, point it to the monitored container, define a delegate for handling changes, and provide a connection to the lease container.
using Microsoft.Azure.Cosmos;
// Setup the Cosmos Client
CosmosClient client = new CosmosClient("your-connection-string");
Container monitoredContainer = client.GetContainer("database", "orders");
Container leaseContainer = client.GetContainer("database", "leases");
// Build the processor
ChangeFeedProcessor processor = monitoredContainer.GetChangeFeedProcessorBuilder<Order>(
processorName: "OrderProcessingProcessor",
onChangesDelegate: HandleChangesAsync)
.WithInstanceName("instance-1")
.WithLeaseContainer(leaseContainer)
.Build();
Step 3: Define the Change Handler
The handler is the method that executes every time a batch of changes is received from the feed.
static async Task HandleChangesAsync(
IReadOnlyCollection<Order> changes,
CancellationToken cancellationToken)
{
foreach (Order order in changes)
{
Console.WriteLine($"Processing order: {order.Id}");
// Perform downstream tasks here, like sending an email or updating an index
}
}
Step 4: Start and Stop the Processor
The processor is a long-running service. You start it when your application initializes and stop it when the application shuts down.
await processor.StartAsync();
// ... application runs ...
await processor.StopAsync();
Advanced Scenarios: Handling Deletions and Large Data
One common question is: "How do I handle deletions?" By default, the Change Feed shows inserts and updates. If you need to track deletions, you must enable "Soft Deletes" in your application logic. Instead of actually deleting a document, you update a flag (e.g., isDeleted: true). Your Change Feed processor then detects this update, performs the necessary cleanup logic, and then you can use a TTL policy on the container to eventually remove the "soft-deleted" document from the database automatically.
Dealing with Large Documents
If your documents are very large, the Change Feed might return fewer documents per batch to avoid exceeding the maximum message size. The Change Feed Processor handles this transparently by grouping changes into batches. However, you should ensure that your HandleChangesAsync method is efficient. If you perform long-running operations inside this method, you will block the processor from moving to the next batch.
Warning: Blocking the Processor Never perform long-running blocking operations inside the
onChangesDelegate. If the handler takes too long, the processor will be delayed in updating the lease, which can lead to lag in your event processing. If you have heavy work to do, offload it to a background queue (like Azure Service Bus or RabbitMQ) and have the Change Feed Processor simply act as a producer to that queue.
Best Practices for Production
When scaling Change Feed implementations, consider these industry standards to maintain reliability and performance:
- Idempotency is Non-Negotiable: Because the Change Feed can, in rare circumstances, deliver the same event twice, your downstream logic must be idempotent. If you are inserting a record into a SQL database based on a Cosmos update, check if the record exists before inserting or use an "upsert" command.
- Monitor Your Lag: You should monitor the "Change Feed Lag," which is the difference between the latest change in the container and the last change processed by your consumer. Azure Monitor provides metrics for this. If the lag increases, it means your processors cannot keep up with the rate of changes.
- Use Multiple Instances: To handle high volumes of changes, deploy multiple instances of your processor. The CFP will automatically balance the partitions across these instances. Ensure each instance has a unique
InstanceName. - Error Handling: Always wrap your logic inside the
onChangesDelegatein atry-catchblock. If your code throws an unhandled exception, the processor will stop. You need to decide whether to log the error and skip the problematic document, or halt the processor to prevent data inconsistency.
Comparison Table: Change Feed vs. Alternatives
| Feature | Change Feed | Polling (SQL Query) | Azure Functions Trigger |
|---|---|---|---|
| Latency | Near real-time | Depends on interval | Near real-time |
| Resource Cost | Low (efficient) | High (repeated RUs) | Low (event-driven) |
| Ordering | Guaranteed | Not guaranteed | Guaranteed |
| Complexity | Moderate | Low | Low (managed) |
| Scalability | High (partition-based) | Poor | High |
Integrating with Azure Functions
Azure Functions provides a built-in "Cosmos DB Trigger" that abstracts almost all of the boilerplate code mentioned above. This is often the preferred way to implement Change Feed logic because it scales automatically and manages the lease container for you.
When using an Azure Function, you simply define the trigger in your function signature:
[FunctionName("ProcessOrderChanges")]
public static void Run(
[CosmosDBTrigger(
databaseName: "orders-db",
containerName: "orders",
Connection = "CosmosConnectionString",
LeaseContainerName = "leases")] IReadOnlyList<Document> documents,
ILogger log)
{
foreach (var doc in documents)
{
log.LogInformation($"Document modified: {doc.Id}");
}
}
This approach is extremely efficient for serverless architectures. You don't have to manage the lifetime of the ChangeFeedProcessor object; the Azure Functions runtime handles the starting, stopping, and scaling of your code based on the volume of changes.
Common Pitfalls and How to Avoid Them
1. The "Poison Document" Problem
A "poison document" is a document that causes your processing logic to crash. If your handler tries to process a document, hits an exception, and crashes, the processor will retry. If the retry also fails, the processor may enter a loop, repeatedly attempting to process the same faulty document.
- Solution: Implement a dead-letter queue or a logging mechanism. If an exception occurs, log the document ID and the error details to a separate table or storage, and then continue with the next document. Do not let one bad document block the entire pipeline.
2. Over-Provisioning Throughput
Developers often over-provision the RUs for the monitored container because they are worried about the Change Feed slowing down the main application.
- Solution: Remember that the Change Feed is a separate read path. While it does consume RUs, it is optimized. Monitor your RU usage and start with a conservative number. Only scale up if you see 429 (Too Many Requests) errors.
3. Ignoring Partition Key Design
The Change Feed is partition-aware. If you have a poorly designed partition key (e.g., a "hot partition" where one partition gets 90% of the traffic), the Change Feed processor will also struggle with that specific partition.
- Solution: Ensure your partition key has high cardinality. This distributes the data—and the subsequent Change Feed processing workload—evenly across the underlying physical partitions of the container.
Callout: The Importance of Idempotency Idempotency means that performing the same operation multiple times results in the same outcome as performing it once. In Change Feed processing, if your service crashes after updating a downstream system but before updating the lease, the system will restart and try to process that same change again. If your logic is not idempotent, you might double-charge a customer or duplicate a log entry. Always design your downstream logic to be "safe" to run multiple times for the same input.
Advanced Topics: Filtering and Projection
Sometimes, you don't need every change. Perhaps you only care about "Order Shipped" events. In the past, you would have to process every change and filter it inside your code. However, with newer versions of the SDK and integration with Azure Functions, you can sometimes apply server-side filtering or use specific change feed modes.
While the standard Change Feed provides the full document, you can also use the "Latest Version" mode. If your application only cares about the current state and doesn't need to see every single update that happened within a millisecond, the Change Feed processor can be configured to focus on the most recent state, effectively ignoring transient intermediate states.
Practical Example: Downstream Synchronization
A classic use case is keeping a Search Index (like Azure Cognitive Search) in sync with your Cosmos DB database.
- Write: The application writes a product update to Cosmos DB.
- Trigger: The Change Feed processor detects the change.
- Process: The processor extracts the relevant fields (Name, Price, Category).
- Sync: The processor pushes these fields to the Search Index via an API call.
- Result: The search index is updated within seconds of the database change without the main application ever knowing about the search engine.
This pattern is highly effective for building "read-optimized" views. Your Cosmos DB is the "source of truth," and the Change Feed allows you to project that data into any format or storage medium required for your specific query needs.
Troubleshooting Performance
If you find that your processor is falling behind, you should check the following:
- Network Latency: Is your processor running in the same Azure region as your Cosmos DB account? Cross-region processing will significantly increase latency and decrease throughput.
- RU Limitations: Check the
RequestChargeproperty in the response headers. If it is consistently hitting your limit, you may need to increase the RU/s of the monitored container. - Batch Size: You can configure the
MaxItemsparameter in your processor. If you have a very high volume of small changes, increasing the batch size can improve throughput by reducing the number of round-trips to the database. - CPU/Memory constraints: If your application is running in a container or a small virtual machine, ensure that you aren't CPU-bound. Processing changes requires parsing JSON and executing your business logic; if the host machine is at 100% CPU, the processor will stall.
Key Takeaways
Implementing Change Feed Notifications is a foundational skill for any developer working with Azure Cosmos DB. By shifting from polling to event-driven processing, you create applications that are more efficient, responsive, and easier to maintain.
- Event-Driven Design: Use the Change Feed to decouple your services. Your database should be the primary record, and downstream systems (analytics, search, notifications) should react to changes via the feed.
- Use the Processor Library: Don't reinvent the wheel. The Change Feed Processor (CFP) library handles partitioning, load balancing, and failure recovery automatically.
- Idempotency is Key: Always design your downstream handlers to be idempotent. Assume the Change Feed might deliver the same event more than once.
- Lease Management: The lease container is the "brain" of the processor. Keep it small, efficient, and well-maintained.
- Monitor Your Lag: Proactive monitoring of your Change Feed lag is the best way to ensure your system remains responsive under load.
- Avoid Blocking: Keep your change handler logic fast. If you have heavy processing to do, use an asynchronous queue to buffer the work.
- Serverless Integration: When possible, use Azure Functions with the Cosmos DB Trigger. It provides the most simplified development experience while maintaining the power and scalability of the underlying Change Feed infrastructure.
By following these practices, you can build systems that handle massive amounts of data updates with grace and reliability, ensuring that your application remains performant even as your data volume grows. Remember, the Change Feed is not just a feature—it is a powerful tool to transform how your data flows through your entire cloud architecture.
Reach the last section to complete this lesson and earn points — you're on section 1 of 11.
- Creating Container Images for Solutions
- Creating Container Images for Solutions Quiz5q
- Publishing Images to Azure Container Registry
- Publishing Images to Azure Container Registry Quiz5q
- Running Containers with Azure Container Instances
- Running Containers with Azure Container Instances Quiz5q
- Creating Solutions with Azure Container Apps
- Creating Solutions with Azure Container Apps Quiz5q
- Creating Azure App Service Web Apps
- Creating Azure App Service Web Apps Quiz5q
- Configuring Diagnostics and Logging
- Configuring Diagnostics and Logging Quiz5q
- Deploying Code and Containerized Solutions
- Deploying Code and Containerized Solutions Quiz5q
- Configuring TLS API Settings and Connections
- Configuring TLS API Settings and Connections Quiz5q
- Implementing Autoscaling
- Implementing Autoscaling Quiz5q
- Configuring Deployment Slots
- Configuring Deployment Slots Quiz5q
- Creating Azure Functions Apps
- Creating Azure Functions Apps Quiz5q
- Implementing Input and Output Bindings
- Implementing Input and Output Bindings Quiz5q
- Implementing Function Triggers
- Implementing Function Triggers Quiz5q
- Durable Functions Patterns
- Durable Functions Patterns Quiz5q
- Function App Hosting Plans
- Function App Hosting Plans Quiz5q
- Local Development and Debugging
- Local Development and Debugging Quiz5q
- Cosmos DB Container and Item Operations
- Cosmos DB Container and Item Operations Quiz5q
- Setting Consistency Levels for Operations
- Setting Consistency Levels for Operations Quiz5q
- Implementing Change Feed Notifications
- Implementing Change Feed Notifications Quiz5q
- Partitioning Strategies in Cosmos DB
- Partitioning Strategies Quiz5q
- Stored Procedures and Triggers
- Stored Procedures and Triggers Quiz5q
- Global Distribution and Replication
- Global Distribution and Replication Quiz5q
- Setting and Retrieving Properties and Metadata
- Setting and Retrieving Properties and Metadata Quiz5q
- Performing Data Operations with SDK
- Performing Data Operations with SDK Quiz5q
- Storage Policies and Lifecycle Management
- Storage Policies and Lifecycle Management Quiz5q
- Access Tiers and Lifecycle Policies
- Access Tiers and Lifecycle Policies Quiz5q
- Blob Leases and Concurrency
- Blob Leases and Concurrency Quiz5q
- Blob Versioning and Soft Delete
- Blob Versioning and Soft Delete Quiz5q
- Microsoft Identity Platform Authentication
- Microsoft Identity Platform Authentication Quiz5q
- Microsoft Entra ID Authentication
- Microsoft Entra ID Authentication Quiz5q
- Creating Shared Access Signatures
- Creating Shared Access Signatures Quiz5q
- Interacting with Microsoft Graph
- Interacting with Microsoft Graph Quiz5q
- Azure App Configuration Security
- Azure App Configuration Security Quiz5q
- Azure Key Vault Implementation
- Azure Key Vault Implementation Quiz5q
- Managed Identities for Azure Resources
- Managed Identities for Azure Resources Quiz5q
- Key Vault Certificates and Secrets
- Key Vault Certificates and Secrets Quiz5q
- Key Vault Access Policies and RBAC
- Key Vault Access Policies and RBAC Quiz5q
- App Configuration Feature Flags
- App Configuration Feature Flags Quiz5q
- Monitoring Metrics Logs and Traces
- Monitoring Metrics Logs and Traces Quiz5q
- Implementing Availability Tests and Alerts
- Implementing Availability Tests and Alerts Quiz5q
- Instrumenting Apps with Application Insights
- Instrumenting Apps with Application Insights Quiz5q
- Distributed Tracing with Application Insights
- Distributed Tracing Quiz5q
- Custom Metrics and Telemetry
- Custom Metrics and Telemetry Quiz5q
- Application Map and Dependencies
- Application Map and Dependencies Quiz5q
- Creating API Management Instances
- Creating API Management Instances Quiz5q
- Creating and Documenting APIs
- Creating and Documenting APIs Quiz5q
- Configuring API Access and Policies
- Configuring API Access and Policies Quiz5q
- API Versioning Strategies
- API Versioning Strategies Quiz5q
- Rate Limiting and Throttling
- Rate Limiting and Throttling Quiz5q
- Backend Services and Transformations
- Backend Services and Transformations Quiz5q
- Implementing Azure Event Grid Solutions
- Implementing Azure Event Grid Solutions Quiz5q
- Implementing Azure Event Hubs Solutions
- Implementing Azure Event Hubs Solutions Quiz5q
- Event Grid Domains and Topics
- Event Grid Domains and Topics Quiz5q
- Event Hubs Capture and Processing
- Event Hubs Capture and Processing Quiz5q
- Custom Events and Dead Lettering
- Custom Events and Dead Lettering Quiz5q
- Implementing Azure Service Bus Solutions
- Implementing Azure Service Bus Solutions Quiz5q
- Implementing Azure Queue Storage Solutions
- Implementing Azure Queue Storage Solutions Quiz5q
- Service Bus Topics and Subscriptions
- Service Bus Topics and Subscriptions Quiz5q
- Message Sessions and Dead Letter Queues
- Message Sessions and Dead Letter Queues Quiz5q
Enjoying the courses?
Everything stays free. Pro shows fewer ads, doubles the points you earn on every lesson and quiz so you progress twice as fast, unlocks half of every practice exam — plus full case studies — with the Learn & Exam study modes, and lets you read each lesson on one page.
- ✓ Fewer advertisements
- ✓ 2× points per lesson & quiz
- ✓ 50% of every exam unlocked
- ✓ Learn & Exam modes
- ✓ Distraction-free lessons