The Azure Cosmos DB Change Feed acts as a persistent transaction log that records document insertions and updates in sorted order per logical partition. It provides an efficient mechanism for triggering asynchronous microservices and maintaining search indexes.
Change Feed Processor vs. Azure Functions Trigger
Developers usually choose between writing custom C# services with the Change Feed Processor library or using the managed Azure Functions Cosmos DB trigger. Azure Functions handles checkpointing, scaling, and partition management automatically behind the scenes.
Implementing an Azure Function Trigger
Below is a production-ready C# Azure Function consuming document updates directly from Cosmos DB:
public static class DocumentProcessorFunction
{
[FunctionName("ProcessContainerChanges")]
public static async Task Run(
[CosmosDBTrigger(
databaseName: "InventoryDb",
containerName: "Products",
Connection = "CosmosDBConnectionString",
LeaseContainerName = "leases",
CreateLeaseContainerIfNotExists = true)] IReadOnlyList<MyDocument> documents,
ILogger log)
{
// Check if any documents were updated or inserted in this batch
if (documents != null && documents.Count > 0)
{
log.LogInformation($"Processing batch of {documents.Count} modified documents.");
foreach (var doc in documents)
{
// Process individual item change, e.g., publish to Event Grid
await ProcessItemChangeAsync(doc);
}
}
}
}A dedicated lease container tracks progress across partition leases, enabling multiple function instances to scale horizontally without duplicate processing.
Cosmos DB’s change feed lets an application react to changes in a container without repeatedly querying it for updates. It’s useful for building projections, moving data to other systems, and triggering background work—but the right design depends on what you expect the feed to represent.
Choose the processing model for the job
For the common latest-version change feed, the Change Feed Processor is a practical choice for continuously running consumers. It distributes work across instances and tracks progress in a lease container. If a worker stops, another instance can pick up its leases. Keep the lease container separate from the source container, and give independent consumer applications their own lease prefix or lease container.
The pull model gives an application more direct control over reading and checkpointing. It can suit custom scheduling or specialized processing, but you take on more of the coordination work. All-versions-and-deletes feed mode has different configuration and API considerations, so check that the chosen SDK and account setup support the mode you need.
Patterns that fit well
Plan for retries and ordering
Design consumers for at-least-once delivery: a batch may be processed again if a worker fails before progress is checkpointed. Make side effects idempotent—for example, use a stable document ID and version or an operation ID to prevent duplicate writes. Avoid checkpointing work before its required downstream action has succeeded.
Changes are ordered within a logical partition, not globally across the container. If ordering matters for an entity, keep that entity’s updates under the same partition key. Don’t assume that events from separate partitions will arrive in a particular order.
One important distinction
The latest-version feed is a view of changed documents, not necessarily a complete business-event log. Multiple updates can leave the consumer with the newest document state rather than every intermediate state, and deletes are not represented in that mode. If your application needs an auditable sequence of business events or must capture deletions, model and emit those events explicitly, or choose a supported feed mode that meets those requirements.
Finally, account for change-feed request units and downstream capacity. A consumer that falls behind can create a growing backlog, so monitor processor health and lag, and scale workers based on the work available—not just the number of application instances.