Azure Cosmos DB

To setup Azure Cosmos DB state store create a component of type . See this guide on how to create and apply a state store configuration.

Warning

The above example uses secrets as plain strings. It is recommended to use a secret store for the secrets as described here.

If you wish to use Cosmos DB as an actor store, append the following to the yaml.

  1. - name: actorStateStore
  2. value: "true"

Spec metadata fields

The Azure Cosmos DB state store component supports authentication using all Azure Active Directory mechanisms. For further information and the relevant component metadata fields to provide depending on the choice of Azure AD authentication mechanism, see the docs for authenticating to Azure.

You can read additional information for setting up Cosmos DB with Azure AD authentication in the .

Follow the instructions from the Azure documentation on how to create an Azure Cosmos DB account. The database and collection must be created in Cosmos DB before Dapr can use it.

Important: The partition key for the collection must be named /partitionKey (note: this is case-sensitive).

In order to setup Cosmos DB as a state store, you need the following properties:

  • URL: the Cosmos DB url. for example: https://******.documents.azure.com:443/
  • Master Key: The key to authenticate to the Cosmos DB account
  • Database: The name of the database
  • Collection: The name of the collection (or container)

Best Practices for Production Use

Azure Cosmos DB shares a strict metadata request rate limit across all databases in a single Azure Cosmos DB account. New connections to Azure Cosmos DB assume a large percentage of the allowable request rate limit. (See the Cosmos DB documentation)

  • Ensure sidecars of applications only load the Azure Cosmos DB component when they require it to avoid unnecessary database connections. This can be done by .
  • Choose deployment strategies that sequentially deploy or start your applications to minimize bursts in new connections to your Azure Cosmos DB accounts.
  • Avoid reusing the same Azure Cosmos DB account for unrelated databases or systems (even outside of Dapr). Distinct Azure Cosmos DB accounts have distinct rate limits.
  • Increase the initTimeout value to allow the component to retry connecting to Azure Cosmos DB during side car initialization for up to 5 minutes. The default value is 5s and should be increased. When using Kubernetes, increasing this value may also require an update to your Readiness and Liveness probes.
  1. spec:
  2. type: state.azure.cosmosdb
  3. version: v1
  4. initTimeout: 5m
  5. metadata:

To use the Cosmos DB state store, your data must be sent to Dapr in JSON-serialized format. Having it just JSON serializable will not work.

If you are using the Dapr SDKs (for example the ), the SDK automatically serializes your data to JSON.

If you want to invoke Dapr’s HTTP endpoint directly, take a look at the examples (using curl) in the Partition keys section below.

Partition keys

For non-actor state operations, the Azure Cosmos DB state store will use the key property provided in the requests to the Dapr API to determine the Cosmos DB partition key. This can be overridden by specifying a metadata field in the request with a key of partitionKey and a value of the desired partition.

The following operation uses nihilus as the partition key value sent to Cosmos DB:

For non-actor state operations, if you want to control the Cosmos DB partition, you can specify it in metadata. Reusing the example above, here’s how to put it under the mypartition partition

  1. curl -X POST http://localhost:3500/v1.0/state/<store_name> \
  2. -H "Content-Type: application/json"
  3. "key": "nihilus",
  4. "value": "darth",
  5. "metadata": {
  6. "partitionKey": "mypartition"
  7. }
  8. }
  9. ]'

For actor state operations, the partition key is generated by Dapr using the appId, the actor type, and the actor id, such that data for the same actor always ends up under the same partition (you do not need to specify it). This is because actor state operations must use transactions, and in Cosmos DB the items in a transaction must be on the same partition.

When using the Dapr Cosmos DB state store and authenticating with Azure AD, you need to perform a few additional steps to set up your environment.

Prerequisites:

  • You need a Service Principal created as per the instructions in the authenticating to Azure page. You need the ID of the Service Principal for the commands below (note that this is different from the client ID of your application, or the value you use for azureClientId in the metadata).
  • jq
  • The scripts below are optimized for a bash or zsh shell

In order to grant your application permissions to access data stored in Cosmos DB, you need to assign it a custom role for the Cosmos DB data plane. In this example you’re going to use a built-in role, “Cosmos DB Built-in Data Contributor”, which grants your application full read-write access to the data; you can optionally create custom, fine-tuned roles following the instructions in the official docs.

  1. # Name of the Resource Group that contains your Cosmos DB
  2. RESOURCE_GROUP="..."
  3. # Name of your Cosmos DB account
  4. ACCOUNT_NAME="..."
  5. # ID of your Service Principal object
  6. PRINCIPAL_ID="..."
  7. # ID of the "Cosmos DB Built-in Data Contributor" role
  8. # You can also use the ID of a custom role
  9. ROLE_ID="00000000-0000-0000-0000-000000000002"
  10. az cosmosdb sql role assignment create \
  11. --account-name "$ACCOUNT_NAME" \
  12. --resource-group "$RESOURCE_GROUP" \
  13. --scope "/" \
  14. --principal-id "$PRINCIPAL_ID" \
  15. --role-definition-id "$ROLE_ID"

When using Cosmos DB as a state store for Dapr, we need to create two stored procedures in your collection. When you configure the state store using a “master key”, Dapr creates those for you, automatically. However, when your state store authenticates with Cosmos DB using Azure AD, because of limitations in the platform we are not able to do it automatically.

If you are using Azure AD to authenticate your Cosmos DB state store and have not created the stored procedures (or if you are using an outdated version of them), your Dapr sidecar will fail to start and you will see an error similar to this in your logs:

To fix this issue, you have two options:

  1. Configure your component to authenticate with the “master key” just once, to have Dapr automatically initialize the stored procedures for you. While you need to use a “master key” the first time you launch your application, you should be able to remove that and use Azure AD credentials (including Managed Identities) after.

To create the stored procedures manually, you can use the commands below.

First, download the code of the stored procedures for the version of Dapr that you’re using. This will create two files in your working directory:

  1. # Set this to the version of Dapr that you're using
  2. DAPR_VERSION="release-1.7"
  3. curl -LfO "https://raw.githubusercontent.com/dapr/components-contrib/${DAPR_VERSION}/state/azure/cosmosdb/storedprocedures/__daprver__.js"
  4. curl -LfO "https://raw.githubusercontent.com/dapr/components-contrib/${DAPR_VERSION}/state/azure/cosmosdb/storedprocedures/__dapr_v2__.js"

Then, using the Azure CLI create the stored procedures in Cosmos DB, for your account, database, and collection (or container):

  1. # Name of the Resource Group that contains your Cosmos DB
  2. RESOURCE_GROUP="..."
  3. # Name of your Cosmos DB account
  4. ACCOUNT_NAME="..."
  5. # Name of your database in the Cosmos DB account
  6. DATABASE_NAME="..."
  7. # Name of the container (collection) in your database
  8. CONTAINER_NAME="..."
  9. az cosmosdb sql stored-procedure create \
  10. --resource-group "$RESOURCE_GROUP" \
  11. --account-name "$ACCOUNT_NAME" \
  12. --database-name "$DATABASE_NAME" \
  13. --container-name "$CONTAINER_NAME" \
  14. --name "__daprver__" \
  15. --body @__daprver__.js
  16. az cosmosdb sql stored-procedure create \
  17. --resource-group "$RESOURCE_GROUP" \
  18. --account-name "$ACCOUNT_NAME" \
  19. --database-name "$DATABASE_NAME" \
  20. --container-name "$CONTAINER_NAME" \
  21. --body @__dapr_v2__.js