Develop Solutions That Use Azure Cosmos DB
Configuring and Managing Container Resources Programmatically
To store data in Azure Cosmos DB, you programmatically create Azure Cosmos DB containers using the SDK. During creation, you must specify a partition key, which is a JSON property used to distribute data across logical partitions. You also configure throughput measured in Request Units (RUs), which can be managed manually or through autoscale to automatically adjust capacity based on workload demand. Additionally, developers configure the consistency level, time-to-live (TTL) rules for data expiration, and indexing policies to optimize database behavior.
The SDK enables full management of both containers and the items they hold. For containers, you can perform setup and teardown tasks, while for items, you can create, read, update, upsert, and delete records. An upsert operation is a versatile choice because it inserts a new item if it does not exist or updates the existing item using its unique Document ID. To retrieve data, the SDK executes SQL-like queries that benefit from automatic indexing, and it supports bulk methods to process multiple items in fewer network rounds.
Achieving high performance requires choosing a partition key with high cardinality to distribute data evenly and avoid hot partitions. You can scale RUs dynamically via the SDK to respond to real-time traffic spikes without paying for idle resources. For global reach, developers configure geo-replication using the SDK, which copies data across multiple regions to lower latency and handle automatic failovers. The SDK also provides built-in retry logic to automatically resolve transient faults, such as brief network drops or throttling events.
Implementing CRUD Operations Using the Cosmos DB SDK
Interacting with the database begins by instantiating a CosmosClient in your application code. From this client, the application obtains a Database object and subsequently a Container object to perform targeted operations. Developers use helper methods like CreateDatabaseIfNotExistsAsync and CreateContainerIfNotExistsAsync to automatically set up resources. This programmatic setup ensures that the infrastructure matches application expectations without requiring manual configuration in the Azure Portal.
Once the container is ready, you can perform basic data operations using specific asynchronous SDK methods. To add data, you call CreateItemAsync, while ReadItemAsync and QueryItemsAsync retrieve documents by their unique identifier or through SQL queries. To modify data, you use ReplaceItemAsync or upsert operations, which can apply optimistic concurrency to prevent overwriting conflicting changes. Finally, when data is no longer needed, DeleteItemAsync removes the document from the physical storage partition.
Every SDK operation interacts with container settings like the partition key, indexing policy, and throughput budget. Choosing an indexing policy allows you to include or exclude specific document paths, which directly balances write speed against query performance. Developers must choose an appropriate consistency level—such as strong, session, or eventual—to balance data freshness against latency. To manage ongoing storage costs and maintain performance, you can enable time-to-live (TTL) settings to automatically purge expired items.
Executing Transactional and Bulk Operations
To execute multiple operations as a single unit of work, the SDK provides the TransactionalBatch class. This class guarantees atomicity, meaning either all operations in the batch succeed or the entire batch is rolled back if any single operation fails. Crucially, all actions within a single TransactionalBatch must target the exact same partition key. This restriction ensures that the database can maintain absolute data consistency across multiple items in a single physical partition.
When migrating large datasets or performing initial loads, you should use bulk execution rather than transactional batches. Bulk execution maximizes throughput by sending many independent requests simultaneously, focusing on high-speed ingestion rather than transaction atomicity. The SDK optimizes network usage by grouping these requests behind the scenes to reduce roundtrips. This approach allows the system to ingest massive amounts of data efficiently without being restricted to a single partition key or transactional boundary.
Executing transactional and bulk operations requires close monitoring of RUs to avoid database throttling. If operations consume more RUs than the provisioned throughput allows, the database will return rate-limiting errors. To prevent this, developers should limit batch sizes to stay under the 2 MB limit, adjust throughput budgets, and write code to handle failures. While the SDK automatically retries transient failures, the application must still capture and handle non-retryable errors like Unauthorized or BadRequest.
Set the Appropriate Consistency Level for Operations
Implement Bounded Staleness for High Availability with Predictable Lag
Bounded staleness is a consistency level in Azure Cosmos DB that gives a predictable compromise between strong consistency and high availability. You configure two parameters: maxStalenessPrefix (the maximum number of stale operations tolerated) and maxIntervalInSeconds (the maximum time lag in seconds). These settings let you fine-tune the trade-off between read consistency, write availability, latency, and throughput. A key advantage is that write region availability is maintained even during network partitions, unlike strong consistency which can drop writes in those situations.
This level fits applications like collaborative editing platforms or financial tracking systems, where users can work with data that may be a few seconds or a limited number of updates old. As long as the staleness stays within the strict, predefined limits, the system does not break. Bounded staleness ensures all users eventually see a consistent state without sacrificing the system's ability to keep accepting writes.
You set the bounded staleness level at the Azure Cosmos DB account level during creation or via an update using ARM templates, Azure CLI, or the portal. Monitor the configured staleness limits to make sure they match your application's tolerance for outdated data. While bounded staleness offers high availability, your application logic must be designed to handle the potential lag—use this level when absolute real-time data freshness is not required, but a tight bound on staleness is.
Session consistency is the most widely used setting in Azure Cosmos DB because it balances performance and data accuracy for individual users. It provides read-your-own-writes semantics: a user always sees the latest data they personally submitted, while other users may see slightly older data. To manage this, Azure uses a unique session token that acts like a bookmark. The client and the database pass this token back and forth, keeping track of the specific version of data the user is working with.
Session consistency offers strong consistency for the individual user while allowing other users to see updates eventually. That makes it ideal for social media feeds, shopping carts, or any app where a person's own actions must be reflected instantly. Users see their own changes immediately, which provides a predictable experience. It also offers lower latency than strong consistency because it does not wait for global updates, and it scales well because the database can handle more traffic efficiently.
To enable it, set the defaultConsistencyLevel to Session in the Azure Cosmos DB account configuration. You can also apply it at the request level by using the session token provided by the server for client-side management. Choose a partition key with many distinct values to distribute the workload evenly. Security is critical: protect session identifiers, avoid exposing them in logs or URLs, validate all input to prevent injection attacks, rotate credentials regularly, and use HTTPS to encrypt session data in transit. Using Microsoft Entra ID for authentication helps secure the connection between the user and the database.
Analyze Consistency Levels and Their Trade-offs
Azure Cosmos DB offers five consistency levels that range from strongest to weakest. Each balances availability, latency, and throughput differently. From strongest to weakest:
- Strong – Guarantees linearizability: all reads return the latest write. Increases latency and reduces write availability because reads must align with the most recent write on every replica.
- Bounded Staleness – Provides an acceptable lag within a configured window of operations or time. Offers a compromise between strong and eventual without sacrificing write availability.
- Session – Guarantees consistency within a single client session using a session token. Provides read-your-writes semantics at low cost.
- Consistent Prefix – Maintains the order of updates globally. Replicas never see updates out of sequence, though they may be behind.
- Eventual – Maximizes availability by allowing replicas to diverge and eventually converge. Has the lowest latency and highest throughput, but no ordering guarantee.
Weaker levels reduce coordination between replicas, which boosts throughput and lowers latency but can return stale data. Stronger levels increase consistency guarantees at the cost of higher latency and lower availability, especially across multiple regions. Choosing the right level means understanding your application's tolerance for stale data and its performance needs.
Use Strong for critical financial or inventory systems where accuracy is paramount. Use Bounded Staleness when you can accept a predictable lag but need high write availability. Session is ideal for user-centric apps that need per-user consistency without global overhead. Consistent Prefix suits scenarios where update order matters but freshness is less critical. Eventual is best for social feeds, telemetry, or any system where speed and availability matter more than absolute freshness. Balancing these trade-offs lets you build scalable, resilient solutions on Azure Cosmos DB.
Implement Change Feed Notifications
Manage Distributed State and Scaling through the Lease Container
The lease container is a special collection in Azure Cosmos DB used to coordinate work when processing a change feed. It acts as a central state manager, keeping track of which parts of the change feed are currently being worked on by different instances of your application. This coordination prevents multiple instances from processing the same data, ensuring every change is handled exactly once.
A core function of the lease container is maintaining checkpoints. These are markers that record the last successfully processed item for each partition. If your application restarts or an instance fails, it can read these checkpoints to resume processing right where it left off, avoiding missed updates or duplicate work. This mechanism provides the foundation for reliable, continuous data processing.
The lease container also enables scaling and fault tolerance. When you add more application instances, the system automatically performs load balancing by reassigning leases between them, spreading the workload. Each instance "owns" its assigned leases. If an instance crashes and stops renewing its lease ownership, that lease will expire after a set time, allowing another healthy instance to acquire it and continue the work, ensuring no data is left unprocessed.
Key settings control this lifecycle of lease acquisition, renewal, and expiration. The LeaseRenewInterval determines how often an instance confirms it's still working. The LeaseExpirationInterval defines how long a lease can be inactive before it's considered abandoned. The LeaseAcquireInterval controls how often instances check for available work. Properly configuring these intervals is crucial for balancing responsiveness with performance overhead.
The Change Feed in Azure Cosmos DB is a persistent, ordered log of all the insert and update operations that happen to items in a container. It does not track deletions. This log enables real-time, event-driven architectures by allowing applications to react to data changes as they occur, rather than repeatedly querying the entire database.
Configuring the change feed involves enabling it on a container and setting up a lease container to track processing progress. You can configure the feed to start reading from the very beginning of the container's history or from a specific point in time. Access to the feed is secured using Azure Cosmos DB roles or managed identities, ensuring only authorized consumers can read the data.
A primary method for consuming the change feed is through Azure Functions using the Cosmos DB trigger. This trigger automatically listens to the feed and invokes your function code whenever documents are changed, passing a batch of the modified items. The function instances use the shared lease container to coordinate, which allows the system to dynamically scale—adding more function instances to handle increased load by automatically redistributing the leases.
Common use cases for the change feed include building event-driven microservices, replicating data to other stores or caches for backup or performance, powering real-time analytics dashboards by streaming changes to analytics engines, and triggering machine learning model retraining when new relevant data arrives.
Design Event-Driven Architectures Using Change Feed
The Azure Cosmos DB change feed is a powerful tool for designing systems that react immediately to data changes. It provides a reliable stream of events (inserts and updates) that can trigger various downstream processes, forming the core of an event-driven architecture.
A fundamental pattern is integrating the change feed with Azure Functions. The Cosmos DB trigger allows serverless code to execute automatically in response to each batch of changes, enabling scenarios like data transformation, aggregation, or sending notifications without managing any servers. The function uses a lease container to maintain its place in the feed reliably.
Beyond Cosmos DB, Azure Blob Storage also offers a change feed. This feature logs all create, update, and delete operations on blobs as ordered, read-only records stored in Apache Avro format. It is useful for scenarios like security auditing, compliance, data protection, and synchronizing blob data with other systems.
When designing with change feeds, several patterns are frequently used. Data Replication involves copying changes to another database or cache to keep it in sync. Event Routing directs specific types of changes to different destinations, like sending customer orders to a payment service and a shipping service. Log Projection transforms the raw change feed into a materialized view optimized for specific queries in a separate store.
Design Event-Driven Workflows with Azure Functions Triggers
Azure Functions triggers are the mechanism that connects events, like changes in a Cosmos DB container, to serverless code execution. This allows developers to build scalable workflows that automatically respond to data modifications without provisioning or managing infrastructure.
The Cosmos DB trigger is specifically designed to listen to a container's change feed. When you configure this trigger, you must specify the monitored container and a separate lease container for state management. The trigger will then invoke your function, passing it the batch of changed documents. You can control performance by adjusting settings like the batch size (how many documents per invocation) and the polling interval (how often to check for changes).
The efficiency of this workflow is directly tied to the performance of the underlying Cosmos DB container. The trigger's ability to read changes depends on the provisioned Request Units (RUs). If the volume of changes is high, insufficient RUs can cause throttling, delaying the processing. A well-designed partition key also helps by allowing changes from different partitions to be processed in parallel by different function instances.
Implementing a change feed notification workflow involves key steps: enabling change feed on the Cosmos DB container, creating a dedicated lease container, and writing an Azure Function with the Cosmos DB trigger binding. The function's code should include robust error handling and retry logic to manage transient failures, ensuring no change is permanently lost due to a temporary issue.
The Change Feed Processor is a library that simplifies reading and processing the change feed from your application code. It handles the complex tasks of reading across all partitions, load-balancing work across multiple consumer instances, and maintaining checkpoints for reliability.
Setting up the processor requires two containers: the monitored container with the data you want to track and a separate lease container for state management. The lease container stores the checkpoint for each partition, recording how far each consumer has processed. You configure the processor to start reading either from the beginning of the feed's history or from the current time.
When configuring the processor, you can tune its behavior. The FeedPollDelay setting controls how long it waits between checks for new changes on each partition. For reliable operation in production, you must implement error handling within your processing logic. The processor itself is resilient, but your code should catch exceptions, log errors, and implement retry policies for operations that fail, such as calls to downstream services.
The Change Feed Processor integrates naturally with scalable architectures. It is the underlying mechanism used by the Azure Functions Cosmos DB trigger. The processor supports dynamic scaling—as you add more instances of your application, it automatically redistributes the leases (and thus the partitions) among them to share the load. This allows your solution to handle growing data volumes efficiently.