A DotNet Raider

My adventures in the .NET world!
posts - 49, comments - 12, trackbacks - 0

My Links

News

Website View Martino Bordin's profile on LinkedIn

Archives

Post Categories

Dapr - State management

Dapr allows the storage of durable data (key\value pairs) across multiple sessions and services.

With Dapr State Management, you can:

  • Save and retrieve state using different stores with 2 levels of consistency (strong and eventual)
  • Use a consistent API to perform operations, abstracting away the implementation details.
  • Implement caching (with TTL) to improve performance.
  • Filter\Sort\Page state entries

Let's see how we can use it in the customer's microservices.

No alt text provided for this image

The customers' microservice persists data in MS SQL Server and caches data in MongoDB

Here's the code:

public class CustomersController : ControllerBase
{
	private readonly ILogger<CustomersController> logger;
	private readonly DaprClient daprClient;
	private readonly ICustomersRepository customerRepository;


	public CustomersController(ILogger<CustomersController> logger, DaprClient daprClient, ICustomersRepository customerRepository)
	{
		this.logger = logger;
		this.daprClient = daprClient;
		this.customerRepository = customerRepository;
	}

	[HttpGet]
	[ProducesResponseType(typeof(IEnumerable<Customer>), (int)HttpStatusCode.OK)]
	public async Task<ActionResult<IEnumerable<Customer>>> GetCustomers()
	{
		var customers = await GetCustomersFromCache();
		return Ok(customers);
	}

	private async Task<IEnumerable<Customer>> GetCustomersFromCache()
	{
		var customers = await daprClient
                              .GetStateAsync<IEnumerable<Customer>>(
                               "mongostore", 
                               "GetCustomers");

		if (customers == null)
		{
			customers = await customerRepository
                              .GetCustomersAsync();
			await daprClient
                            .SaveStateAsync("mongostore", 
                                            "GetCustomers", 
                                            customers);
		}

		return customers;
	}
}
  

We have a standard API Controller where we inject the DaprClient (view the previous article to see the NuGet package required and how to register it).

In the GetCustomersFromCache method, we use the GetStateAsync to check if we previously cached the data. If yes, we just return it; if no, we load it (using the customer repository), cache it using the SaveStateAsync and return it.

Please note that we are specifying where we want to save our state by passing the store name (in our case "mongostore"). But where is it defined?

If you remember in the previous article we configured the sidecar with the component path; that's the folder where we store the configurations of our components.

Therefore, we just have to create under that folder a new YAML file with the following configuration

apiVersion: dapr.io/v1alpha
kind: Component
metadata:   name: mongostore
spec:   type: state.mongodb   version: v1   metadata:   - name: host     value: "mongo:27017"

The value "mongostore" in the metadata section is the store name we have to use in our code (I set it as "mongostore", but you can follow your preferred naming convention). We also specify how to connect to the MongoDB store.

Where can you find all these settings? In the official documentation, of course!

Now we have all the information to use another state store (i.e. Redis) as I've done in the products microservice.

The products' microservice persists data in PostgreSQL and cache data in Redis

The relevant piece of code is similar to the previous one:

private async Task<IEnumerable<Product>> GetProductsFromCache(
{
	var products = await daprClient
                         .GetStateAsync<IEnumerable<Product>>(
                                                              "redisstore", 
                                                              "GetProducts");
	if (products == null)
	{
		products = await this.productRepository.GetProductsAsync();
		await daprClient.SaveStateAsync("redisstore", "GetProducts", products);
	}

	return products;
})

To configure the Redis state store, we create the following file in the component's folder

apiVersion: dapr.io/v1alpha
kind: Component
metadata:   name: redisstore
spec:   type: state.redis   version: v1   metadata:   - name: redisHost     value: redis:6379   - name: redisPassword     value: ""

To test both customers' and products' microservices, I prepared 2 .http files with the sample GET requests, so we can use Visual Studio.

Just start the solution (using the docker-compose) and executes both requests.

When executing the GET /customers, the result will be cached in Mongo

In the source code on GitHub, you can see also how to delete the state and how to set a TTL of the cached value (otherwise cache will never expire!).

In the next article, we'll see the Configuration and Binding building blocks

Print | posted on mercoledì 6 settembre 2023 17:54 | Filed Under [ Dapr Microservices ]

Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET