Configure a Sync Dapr State Store Reaction
The Sync Dapr State Store Reaction materializes the results of Drasi Continuous Queries into a Dapr state store. It performs an initial bulk load of all query results and then incrementally processes changes (adds, updates, deletes) from a Continuous Query to keep the Dapr state store up-to-date.
This enables Dapr-based microservices to easily access sophisticated, pre-computed, and continuously updated data views through the standard Dapr state management API.
Scenarios powered by this reaction
This reaction can power several vital scenarios for Dapr users:
- Simplified Composite API Implementation: Pre-compute and materialize aggregated data views from multiple sources. API-serving microservices can then read this data directly from Dapr State with low latency, simplifying their logic.
- Building New Functionality without Disruption: Introduce new features or services that consume tailored data views from existing systems without modifying those original services. In Drasi, Continuous Queries transform and project data, and this reaction makes it available in Dapr State for new microservices.
- Efficient Query Side of CQRS: Use Drasi Continuous Queries to define and maintain read models for CQRS. The reaction materializes these optimized query views into Dapr State, allowing query-handling microservices to read them efficiently.
- Decoupled Data Views: Provide different microservices with specific “slices” or perspectives of the same underlying data, each materialized in Dapr State for easy consumption.
- Improved Read Performance: Offload complex querying from source databases by having read-optimized views readily available in a Dapr state store, accessed via simple key-value lookups.
Requirements
On the computer from where you will create the Reaction, you need the following software:
- Drasi CLI
- Kubectl (for Dapr component configuration)
- Note the namespace in which Drasi was installed. By default, Drasi uses
drasi-system
namespace. If you chose a custom namespace during installation of Drasi, use that in place ofdrasi-system
when configuring the reaction.
Dapr Environment Prerequisites
Before deploying this reaction, ensure the following are in place in your Kubernetes environment:
-
Application’s Dapr State Store: Your Dapr microservice(s) (e.g., running in
my-app-namespace
) must have a Dapr state store component configured and deployed. This component tells your application’s Dapr sidecar how to connect to the underlying state store (e.g., Redis, Cosmos DB). Let’s say this component is namedmystatestore
. -
Data Store Accessibility: The actual data store (e.g., your Redis instance) that backs your Dapr state component must be network-accessible from the Kubernetes namespace in which drasi was installed (default:
drasi-system
). This is because the Drasi Reaction pod runs indrasi-system
(or the namespace chosen during installation) and will need to connect to this data store. -
Crucial: Dapr State Store Component for Drasi in
drasi-system
Namespace: This is a key step. The DrasiSyncDaprStateStore
Reaction runs as a pod in the Kubernetes namespace in which Drasi was installed (default:drasi-system
). Like any Dapr-enabled application, it relies on its own Dapr sidecar (running alongside it indrasi-system
) to interact with Dapr building blocks, including state stores. Therefore, you must deploy a Dapr state store component manifest specifically for the Drasi Reaction in thedrasi-system
namespace. This component tells the Reaction’s Dapr sidecar how to connect to your existing state store.metadata.name
: Thename
of this Dapr component indrasi-system
must match thestateStoreName
you will specify in the Drasi Reaction’s configuration (seespec.queries
later). For example, if your application uses a state store component namedmystatestore
, and you want the Reaction to write to it, you will create a component also namedmystatestore
in thedrasi-system
namespace.metadata.namespace
: This component manifest must specifynamespace: drasi-system
.spec
(type, version, metadata/connection details): Thespec
section of this component (includingtype
,version
, and all connectionmetadata
likeredisHost
,redisPassword
, etc.) must be identical to the Dapr state store component used by your application. It needs to point to the same underlying physical state store.spec.metadata.keyPrefix
: IMPORTANT! For both the application’s Dapr state store component AND the corresponding component indrasi-system
, it is highly recommended to explicitly set thekeyPrefix
strategy to"none"
. This ensures that the keys used by the Drasi Reaction (derived directly from thekeyField
in your query results) are stored and retrieved without any automatic Dapr-managed prefixes. This consistency is vital for both the Reaction and your application to access the same data items using the same keys.# Example snippet for spec.metadata in your Dapr component # ... spec: type: state.redis # Or your chosen state store type version: v1 metadata: - name: redisHost value: your-shared-redis.default.svc.cluster.local:6379 - name: redisPassword value: "yourRedisPassword" - name: keyPrefix # Add this line value: "none" # Explicitly set to "none" # ...
Why is
keyPrefix: "none"
important? IfkeyPrefix
is not set to"none"
(e.g., it defaults toappid
or is explicitly set to another strategy), Dapr will automatically add prefixes (like the Dapr App ID) to the keys. The Drasi Reaction writes keys based purely on your query’skeyField
. If your application’s Dapr component expects prefixed keys, it won’t find the data written by the Reaction, and vice-versa. SettingkeyPrefix: "none"
on both components ensures that the rawkeyField
value is the actual key in the underlying store, accessible by both.Example Structure:
Let’s say your application in
my-app-namespace
uses a Redis state store defined inmy-app-components/app-statestore.yaml
:# filepath: my-app-components/app-statestore.yaml apiVersion: dapr.io/v1alpha1 kind: Component metadata: name: mystatestore # Name used by your application namespace: my-app-namespace # Your application's namespace spec: type: state.redis version: v1 metadata: - name: redisHost value: your-shared-redis.default.svc.cluster.local:6379 # Points to your actual Redis - name: redisPassword value: "yourRedisPassword" - name: keyPrefix # Explicitly set this to none value: "none" # ... other configurations
You must create a corresponding Dapr component for Drasi in the namespace in which drasi was installed (by default,
drasi-system
), for example, indrasi-components/drasi-statestore-access.yaml
:# filepath: drasi-components/drasi-statestore-access.yaml apiVersion: dapr.io/v1alpha1 kind: Component metadata: name: mystatestore # CRITICAL: Same name as your app's component if the Reaction targets it namespace: drasi-system # CRITICAL: Must be drasi-system (or the namespace in which drasi was installed) spec: type: state.redis # Identical spec to your app's component version: v1 metadata: - name: redisHost # Identical connection details value: your-shared-redis.default.svc.cluster.local:6379 # Points to the SAME actual Redis - name: redisPassword value: "yourRedisPassword" - name: keyPrefix # Explicitly set this to none value: "none" # ... other configurations identical to your app's component
Apply this second component definition to your Kubernetes cluster:
kubectl apply -f drasi-components/drasi-statestore-access.yaml
This allows the Drasi Reaction (via its sidecar in
drasi-system
) to find and use the Dapr component namedmystatestore
to write to your shared Redis instance.
Registering the Reaction Provider (If Necessary)
The Drasi environment needs to be aware of the SyncDaprStateStore
reaction type.
-
Check if registered:
drasi list reactionprovider
Look for
SyncDaprStateStore
in the output. -
If not listed, register it: Create a
reaction-provider.yaml
file:# filepath: reaction-provider.yaml apiVersion: v1 kind: ReactionProvider name: SyncDaprStateStore spec: services: reaction: image: drasi-project/reaction-sync-dapr-statestore:latest # Use the correct image name and tag for your reaction
Apply it:
drasi apply -f reaction-provider.yaml
Creating the Reaction
To create a Reaction, execute the drasi apply
command as follows:
drasi apply -f my-sync-dapr-reaction.yaml
The -f
flag specifies that the definition of the new Reaction is contained in the referenced YAML file my-sync-dapr-reaction.yaml
.
Reaction Definition
Here is an example of a SyncDaprStateStore
Reaction definition:
# filepath: my-sync-dapr-reaction.yaml
kind: Reaction
apiVersion: v1
name: my-app-state-synchronizer # A unique name for your reaction instance
spec:
kind: SyncDaprStateStore # Must match the registered ReactionProvider name
queries:
# Example 1: Sync results from 'orders-ready-for-pickup' query
# This will use the Dapr component named 'mystatestore' in the drasi-system namespace
orders-ready-for-pickup: '{"stateStoreName": "mystatestore", "keyField": "orderId"}'
# Example 2: Sync results from 'active-user-profiles' query
# This will use the Dapr component named 'userprofilecache' in the drasi-system namespace
active-user-profiles: '{"stateStoreName": "userprofilecache", "keyField": "profileId"}'
In this definition:
apiVersion
must bev1
.kind
property tells Drasi to create aReaction
resource.name
property is the unique identity of the Reaction within the Drasi environment.spec.kind
property tells Drasi the type of Reaction to create, in this caseSyncDaprStateStore
.
This table describes the settings in the spec
section:
Property | Description |
---|---|
queries |
An object where each key is the name of a Drasi Continuous Query to subscribe to. The value for each key is a JSON string specifying the configuration for that query’s synchronization. |
The JSON string for each query must contain: | |
- stateStoreName (string): The metadata.name of the Dapr state store component (e.g., "mystatestore" , "userprofilecache" ) that the Reaction should use. It is important to note that this refers to the Dapr component defined in the namespace in which drasi was installed (by default - drasi-system ). |
|
- keyField (string): The name of the field within each result item from the Drasi Continuous Query that will be used as the unique key when storing that item in the Dapr state store. |
How Dapr Microservices Access the Synchronized Data
Once the reaction is running and has synchronized data into the shared underlying state store (e.g., your Redis instance):
Your Dapr microservices (running in their own namespace, e.g., my-app-namespace
) can access this data using their standard Dapr state management client SDKs. They will target their own Dapr state store component (e.g., mystatestore
in my-app-namespace
), which points to the same underlying physical store that the Drasi Reaction is writing to.
Example (C# using Dapr.Client):
// In your Dapr microservice (e.g., in my-app-namespace)
using Dapr.Client;
// ...
var daprClient = new DaprClientBuilder().Build();
// Your app uses its 'mystatestore' component, which points to the same Redis
// as the 'mystatestore' component in 'drasi-system' used by the Reaction.
string daprStateStoreNameForApp = "mystatestore";
string orderIdToFetch = "some-specific-order-id"; // This key comes from the 'keyField' of a query result
var orderDetails = await daprClient.GetStateAsync<MyOrderDataType>(daprStateStoreNameForApp, orderIdToFetch);
if (orderDetails != null)
{
// Process orderDetails
Console.WriteLine($"Fetched order: {orderDetails.CustomerName}");
}
else
{
Console.WriteLine($"Order with ID {orderIdToFetch} not found in {daprStateStoreNameForApp}.");
}
// Define MyOrderDataType according to the structure of your query results
// public class MyOrderDataType {
// public string OrderId { get; set; } // Matches 'keyField' if it's part of the data
// public string CustomerName { get; set; }
// // ... other fields from your query result
// }
Inspecting the Reaction
As soon as the Reaction is created it will start running. You can check its status:
drasi list reaction
Example output:
ID | AVAILABLE
--------------------------------+------------
my-app-state-synchronizer | true
If an error occurs, the AVAILABLE
column will show the error.
For more details:
drasi describe reaction my-app-state-synchronizer
This returns the full definition and detailed status.
Modifying the Reaction
To modify the reaction (e.g., change subscribed queries or their configurations), update your YAML file and re-apply it using the same drasi apply
command with the same reaction name:
drasi apply -f my-sync-dapr-reaction.yaml
Deleting the Reaction
To delete a Reaction:
- By type and name:
drasi delete reaction my-app-state-synchronizer
- Using the YAML file(s):
drasi delete -f my-sync-dapr-reaction.yaml
This is useful if a single YAML file defines multiple resources.