Change Feed Estimator

Earn 25 points (50 with Pro) in two steps

  1. ① Read through the lesson — each section gets a ✓ as you scroll through it.
  2. ② When every section has a ✓, tap Complete lesson.

0 of 11 read · keep scrolling

✦ See fewer ads and earn double points — 50 a lesson instead of 25 — with Pro

Mastering the Azure Cosmos DB Change Feed Estimator

Introduction: Why Monitoring Matters in Event-Driven Architectures

In modern distributed systems, data rarely sits idle. We ingest data, transform it, move it to analytical stores, and trigger downstream processes based on state changes. Azure Cosmos DB facilitates this through its Change Feed mechanism, which provides a persistent, ordered record of modifications made to items within a container. However, as your system scales, simply consuming the feed is not enough. You need to understand the "lag"—the distance between the latest write in your database and the point up to which your processor has read.

This is where the Change Feed Estimator comes into play. Without a reliable way to measure this lag, you are effectively flying blind. If your consumer service falls behind, you might experience delayed updates, stale data in your search indexes, or slow-moving business processes that rely on real-time triggers. The Change Feed Estimator provides a window into the health of your event-driven pipeline, allowing you to proactively scale your compute resources, troubleshoot bottlenecks, and ensure that your data processing keeps pace with incoming traffic.

In this lesson, we will explore the mechanics of the Change Feed Estimator, how to integrate it into your .NET applications, and how to use the data it provides to make informed architectural decisions. We will move beyond the basics to discuss how the estimator functions under the hood, the impact of partition distribution, and how to build monitoring dashboards that actually help you maintain a high-performance system.

Not read yet

Understanding the Change Feed and the Concept of Lag

Before diving into the estimator, we must clarify what we mean by "lag." In the context of Azure Cosmos DB, the Change Feed is a stream of events. When you use the Change Feed Processor library, you maintain a "lease" container. This container tracks the progress of your processing by recording the state (the continuation token) for each logical partition.

Lag is defined as the difference between the most recent sequence number (or LSN - Log Sequence Number) in the physical partition and the sequence number currently stored in your lease document. If your processor is reading at the same speed as the data is being written, the lag is effectively zero. If the write volume spikes or your processing logic becomes computationally expensive, the processor will fall behind, and the lag will increase.

Callout: The Difference Between Throughput and Latency It is common to confuse throughput with latency. Throughput refers to the volume of data your system can handle, whereas latency (or lag) refers to the time it takes for a specific change to be processed. The Change Feed Estimator specifically measures the "processing backlog," which is a metric of latency. Monitoring this metric is vital because a system can have high throughput but still suffer from severe, growing lag if the processing logic cannot keep up with the incoming rate of change.

Not read yet

How the Change Feed Estimator Works

The Change Feed Estimator is a utility provided within the Azure Cosmos DB .NET SDK that calculates the pending work. It does this by querying the metadata of the physical partitions and comparing the latest LSN with the LSN stored in the lease container.

When you initialize the estimator, it periodically polls the lease container and the physical partition metadata. It doesn't actually read the documents themselves, which is a crucial distinction. Because it only looks at metadata, the estimator is very lightweight and does not consume significant Request Units (RUs) or add latency to your actual data processing logic.

Key Components of the Estimation Process

  • Lease Container: This is the source of truth for where your processor currently stands. The estimator reads these documents to understand the last processed LSN.
  • Physical Partitions: Azure Cosmos DB splits data into physical partitions based on throughput and size. The estimator must query each of these partitions to identify the "latest" LSN available.
  • The Calculation: For each partition, the estimator subtracts the last processed LSN from the latest available LSN. The sum of these values across all partitions gives you the total pending items to be processed.

Not read yet

Implementing the Change Feed Estimator in .NET

To implement the estimator, you need an existing Change Feed Processor setup. The estimator is usually run as a separate background task or integrated into a monitoring service that runs alongside your main processor.

Step-by-Step Implementation Guide

  1. Define your Container References: You need access to both the monitored container (where data is written) and the lease container (where progress is saved).
  2. Initialize the Processor: Ensure your ChangeFeedProcessor is correctly configured so that it is actively updating the lease container.
  3. Build the Estimator: Use the GetChangeFeedEstimatorBuilder method available on the Container class.
  4. Register a Handler: Define a callback function that will receive the estimated lag value. This is where you will log the data to Application Insights, Prometheus, or your preferred monitoring tool.
  5. Start the Estimator: Start the instance to begin polling the metadata.

Code Example: Basic Estimator Setup

// Define the containers
Container monitoredContainer = cosmosClient.GetContainer("database", "sourceContainer");
Container leaseContainer = cosmosClient.GetContainer("database", "leases");

// Build the estimator
ChangeFeedEstimator estimator = monitoredContainer.GetChangeFeedEstimatorBuilder(
    processorName: "my-processor",
    leaseContainer: leaseContainer)
    .WithEstimationHandler(async (long estimatedLag, CancellationToken ct) =>
    {
        // Log the lag to your monitoring system
        Console.WriteLine($"Current pending items: {estimatedLag}");
        await Task.CompletedTask;
    })
    .Build();

// Start the estimation process
await estimator.StartAsync();

Note: The processorName must exactly match the name used in your ChangeFeedProcessor configuration. If they do not match, the estimator will look at the wrong lease documents and report incorrect (or zero) lag.

Not read yet

Best Practices for Production Monitoring

Monitoring lag is not a "set it and forget it" task. To gain real value from the Change Feed Estimator, you must integrate it into a robust observability strategy.

1. Frequency of Estimation

Do not poll the estimator every millisecond. The metadata query, while lightweight, still has a cost. A polling interval of 5 to 15 seconds is usually sufficient for most production systems. If your system requires extremely tight latency requirements, you might go as low as 1 second, but ensure you are accounting for the RU cost in your capacity planning.

2. Alerting Strategies

Instead of just logging the lag, set up alerts based on thresholds. For example:

  • Warning: Lag exceeds 5,000 items (indicates a potential slowdown).
  • Critical: Lag exceeds 50,000 items (indicates a stuck processor or a massive spike in traffic that requires manual intervention or horizontal scaling).

3. Correlate with Other Metrics

Lag is a symptom, not a root cause. When you see an increase in lag, you should simultaneously check:

  • RU Consumption: Is the processor hitting its provisioned throughput limit?
  • Processor CPU/Memory: Is the compute instance running the processor experiencing resource exhaustion?
  • Exception Rates: Are there transient errors in the processing logic causing retries, which in turn slow down the consumption of the feed?

Not read yet

Common Pitfalls and How to Avoid Them

Even experienced engineers run into issues when implementing the Change Feed Estimator. Being aware of these pitfalls can save you hours of debugging time.

The "Missing Lease" Trap

If you deploy a new version of your processor with a different processorName, the estimator will look for a new set of leases. If those leases don't exist yet, it might report a lag of zero even if you have millions of items waiting to be processed. Always ensure that your processor name is consistent across deployments unless you intentionally want to restart the feed from the beginning.

Underestimating Throughput Requirements

Sometimes, the act of monitoring creates its own load. If you have a very large number of physical partitions, the estimator has to perform multiple requests to gather the LSNs for each one. If your container is under-provisioned, the estimator itself might start getting throttled (429 errors), which can cause the estimation to become inaccurate or delayed.

Ignoring Partition Key Distribution

If your data is poorly partitioned (e.g., a "hot" partition key), the Change Feed Processor might be working correctly for 99% of your data but failing on a single partition that is overwhelmed. The estimator provides an aggregate number, but it can hide these partition-level bottlenecks. If you see consistent lag, check if the work is being distributed evenly across your physical partitions.

Callout: Why Aggregate Lag Can Be Deceptive The estimator provides a total count of pending items. While this is helpful for high-level monitoring, it doesn't tell the whole story. If your total lag is 1,000 items, but 999 of them are concentrated in one specific physical partition, your consumer will still be slow. Always keep an eye on your partition key distribution to ensure that the "work" of processing is spread evenly across your available compute instances.

Not read yet

Comparison: Estimator vs. Manual Monitoring

Feature Change Feed Estimator Manual Querying (LSN)
Ease of Use High (Native SDK support) Low (Requires custom logic)
Performance Optimized for metadata High overhead (requires querying)
Accuracy Real-time approximation Precise but slow
Maintenance Minimal High (requires manual tracking)

Advanced Integration: Pushing Metrics to External Dashboards

To make the Change Feed Estimator truly useful, you should push the data to a visualization tool like Grafana or Azure Monitor. By converting the long estimatedLag into a time-series metric, you can visualize trends over time.

For instance, you might notice that lag consistently spikes every day at 2:00 AM. This could correlate with a scheduled batch job that performs bulk updates on your container. By visualizing this, you can adjust your scaling policies to automatically increase the throughput of your consumer service just before the batch job starts, and scale it back down once the lag returns to normal.

Example: Pushing to Application Insights

.WithEstimationHandler(async (long estimatedLag, CancellationToken ct) =>
{
    var telemetry = new TelemetryClient();
    telemetry.TrackMetric("ChangeFeedLag", estimatedLag);
    await Task.CompletedTask;
})

This simple addition allows you to create an "Azure Monitor Workbook" that displays a graph of your lag over the last 24 hours. When you observe that the lag is trending upward, you have empirical evidence that your current consumer capacity is insufficient for your current data ingestion rate.

Not read yet

Troubleshooting Performance Issues

When the estimator reports high lag, you have three primary levers to pull to resolve the issue:

  1. Scale the Processor: If the processor is CPU-bound, increase the instance size. If the processor is I/O-bound, consider adding more instances of the processor to distribute the partitions across multiple consumers.
  2. Optimize the Processing Logic: Is there a database call inside your HandleChangesAsync method? If you are making a network call to an external API for every document, you are likely introducing massive latency. Try to batch these calls or use asynchronous patterns to improve throughput.
  3. Increase Throughput on the Monitored Container: Sometimes the processor is waiting for the source container to provide the data. If the monitored container is at its RU limit, the Change Feed will be throttled. Ensure your source container has enough RUs to handle both the writes and the reads from the Change Feed processor.

Not read yet

Important Architectural Considerations

When designing your system, it is vital to remember that the Change Feed is an "at-least-once" delivery mechanism. This means that under certain conditions—such as a process crash or a network failure—the processor might re-process some items. Your application logic must be idempotent.

An idempotent operation is one that can be applied multiple times without changing the result beyond the initial application. For example, if your processor updates an external SQL database, use "upsert" logic (Update or Insert) rather than just "insert." If the processor re-reads a document it already processed, the upsert will simply overwrite the existing record with the same value, preventing data corruption.

Warning: Never assume that the Change Feed will deliver items exactly once. If your processing logic involves incrementing a counter or sending an email, you must build state tracking into your logic to detect and ignore duplicates. The Change Feed Estimator helps you monitor the queue, but it does not prevent duplicate processing.

Not read yet

Scaling with the Change Feed Processor

The Change Feed Processor is designed to scale horizontally. You can run multiple instances of your processor, and they will automatically negotiate the distribution of partitions among themselves using the lease container. As your data volume grows, you can simply add more instances of your processor application.

When you add a new instance, the existing instances will detect the new member, rebalance the leases, and some partitions will be handed over to the new instance. During this rebalancing period, you might see a temporary spike in the estimated lag. This is normal behavior as the new instance initializes its state and begins catching up on its assigned partitions.

Dealing with Large Volumes of Data

If your system is processing millions of items per hour, the estimator is your best friend for capacity planning. Use the estimator to establish a baseline of "normal" lag. Once you have this baseline, any deviation becomes an actionable alert.

Consider these scenarios for proactive scaling:

  • Predictable Spikes: If you have known periods of high activity, use Azure Functions with a timer trigger or a custom scaling logic to pre-warm your consumer instances.
  • Unpredictable Spikes: If your traffic is bursty and unpredictable, use the lag reported by the estimator to trigger an auto-scale event. If the lag exceeds a certain threshold for more than five minutes, spin up additional compute resources.

Not read yet

Summary: A Checklist for Success

To wrap up, here is a checklist to ensure your Change Feed implementation and monitoring are production-ready:

  • Name your processors uniquely: Never reuse names across different environments or logic versions.
  • Monitor the estimator: Do not rely on the processor to tell you it is healthy; use the estimator to quantify its progress.
  • Set alerts: Define clear thresholds for "Warning" and "Critical" lag levels.
  • Ensure idempotency: Build your logic to handle the reality of "at-least-once" processing.
  • Check RU limits: Ensure both the source and the consumer have sufficient throughput to support the processing velocity.
  • Optimize the consumer: Avoid heavy synchronous operations in your processing loop.
  • Visualize the data: Integrate the estimator with a dashboard to identify trends and plan for future capacity needs.

Key Takeaways

  1. The Change Feed Estimator is a diagnostic tool: It is not part of the data flow itself, but rather an essential observability component that measures the backlog of unprocessed changes.
  2. Metadata-only polling: The estimator is lightweight because it queries partition metadata rather than the items themselves, making it safe to use in high-throughput environments when configured with reasonable polling intervals.
  3. Lag as a key performance indicator: Lag is the most accurate measure of how well your event-driven system is keeping up with real-time data. High lag is a clear signal that your architecture needs optimization or additional scaling.
  4. Consistency is vital: The processorName must match between the processor and the estimator for the metrics to be accurate. Mismatched names will lead to misleading or non-existent lag reports.
  5. Idempotency is mandatory: Because the Change Feed guarantees at-least-once delivery, your processing code must be designed to handle duplicate events without causing side effects or data integrity issues.
  6. Proactive monitoring leads to better scaling: By tracking lag over time, you can move from reactive troubleshooting to proactive capacity planning, ensuring that your system remains responsive even during peak traffic periods.
  7. Integration is key: Don't just log lag to a console; push it to a time-series database or monitoring service where it can be visualized, alerted upon, and correlated with other system metrics.

By mastering the Change Feed Estimator, you transition from simply "using" Cosmos DB to "managing" a sophisticated, scalable, and observable event-driven architecture. This tool is the bridge between a system that works in development and a system that remains resilient in the face of the unpredictable demands of a production environment.

Not read yet

Each section gets a ✓ as you scroll through it. Tap the button to jump to the next one.