Microsoft Orleans: Grain Caches
Tags: programming, csharp, netcore, microsoftorleans
Published: 2022-12-15 17:21:50

---
title: Microsoft Orleans: Grain Caches
published: true
date: 2022-12-15 16:00:00 UTC
tags: programming,csharp,netcore,MicrosoftOrleans
canonical_url: https://blog.kritner.com/2022/10/14/microsoft-orleans-grain-caches/
series: Microsoft Orleans
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y83j5kl50mx0plx4gwlp.png


---

Holy moly it’s been a while. Time for some more Orleans goodness, hopefully? Caches!

## Overview

What are caches and what do they do? As usual, going to lean on Wikipedia to help me out:

From [https://en.wikipedia.org/wiki/Cache\_(computing)](https://en.wikipedia.org/wiki/Cache_(computing)):

> In computing, a cache is a hardware or software component that stores data so that future requests for that data can be served faster; the data stored in a cache might be the result of an earlier computation or a copy of data stored elsewhere.

So basically a means of getting data faster, sign me up!

Often, you’ll see multiple levels of caching on varying pieces of infrastructure, whether those pieces are all contained within a single piece of hardware (like a computer), or spread across multiple pieces of hardware (like a network). We have the need for speed, and caches gonna give it to ya… ideally!

## Problems with caching

[https://aws.amazon.com/builders-library/caching-challenges-and-strategies/](https://aws.amazon.com/builders-library/caching-challenges-and-strategies/) has a lot of good information, but just to name a few:

- Stale data
- Inconsistent data across caches
- In the case of local caches - memory and/or additional CPU pressure on a system that is otherwise acting as a webserver
- In the case of external caches - additional system complexity, additional hop to get to data (though seemingly still better than having to rerun some sort of querying/aggregating of data from potentially numerous data sources when not caching)

## A (naive) Orleans Cache

So, it’s been a while since I’ve written _anything_, much less about Orleans. It’s Hacktoberfest though so I at least gotta try to get that shirt!

Like in past posts where I’m demonstrating something Orleansly, we’ll be working from my github repo starting here [https://github.com/Kritner-Blogs/OrleansGettingStarted/releases/tag/v0.62.0](https://github.com/Kritner-Blogs/OrleansGettingStarted/releases/tag/v0.62.0). Prior to us creating another `IOrleansFunction`, we actually need to write the thing we’re be demonstrating, the cache!

A cache abstraction can (and perhaps should?) have more methods available to it than what we’ll be doing in this post, but this isn’t meant to be a full fledged solution.

```cs
public interface IOrleansCache<TValue> : IGrainWithStringKey, IGrainInterfaceMarker
{
    Task AddOrUpdate(string key, TValue value);
    Task<TValue> Get(string key);
}
```

The above should look pretty straight forward, but just to go over it anyway:

- `TValue` is the type of value our cache will be storing
- `IGrainWithStringKey` states that cache will have a string primary key
- `AddOrUpdate` - for adding/updating `value`s based on a string `key` (not to be confused with the grain primary key)
- `Get` for retrieving a `value` from the cache based on a string `key`

In case it isn’t obvious, we have two “keys” in the above declaration. A grain “primary” key, and a “key value pair” key. What’s the difference? Well by having the primary key be a string, we can get different grain instances for each individual string key we provide. Why would we do that? You may have different caches with different value types you want to store, bring up a different cache per customer, or a bit of both.

As for the implementation of the grain, I’m leaning heavily on an LRU cache from the package [https://github.com/bitfaster/BitFaster.Caching/](https://github.com/bitfaster/BitFaster.Caching/).

```cs
public class OrleansLruCache<TValue> : Grain, IOrleansCache<TValue>
{
    private readonly ConcurrentLru<string, TValue> _cache;

    public OrleansLruCache()
    {
        _cache = new ConcurrentLru<string, TValue>(50);
    }

    public Task AddOrUpdate(string key, TValue value)
    {
        _cache.AddOrUpdate(key, value);
        return Task.CompletedTask;
    }

    public Task<TValue> Get(string key)
    {
        if (_cache.TryGet(key, out var result))
            return Task.FromResult(result);

        TValue nullResult = default;
        return Task.FromResult(nullResult);
    }
}
```

Again this should all be pretty self explanatory, just a plain old consuming of a cache and not (currently) worrying about things like parameterizing configuration, providing cache eviction methods, persisting the cache to disk in any way, etc.

## Wrap up

Keeping this one pretty short and sweet, I implemented within the final code (found here [https://github.com/Kritner-Blogs/OrleansGettingStarted/releases/tag/v0.63.0](https://github.com/Kritner-Blogs/OrleansGettingStarted/releases/tag/v0.63.0)) our `IOrleansFunction` so it can be played around with. I might have another post or two this month elaborating on this some more, just cuz I need to do some more PRs! (And get back into the habit of writing, but this is at least the 50th time I’ve said that)

## References

- [https://en.wikipedia.org/wiki/Cache\_(computing)](https://en.wikipedia.org/wiki/Cache_(computing))
- [https://aws.amazon.com/builders-library/caching-challenges-and-strategies/](https://aws.amazon.com/builders-library/caching-challenges-and-strategies/)
- [https://github.com/bitfaster/BitFaster.Caching/](https://github.com/bitfaster/BitFaster.Caching/)
- Code (beginning) [https://github.com/Kritner-Blogs/OrleansGettingStarted/releases/tag/v0.62.0](https://github.com/Kritner-Blogs/OrleansGettingStarted/releases/tag/v0.62.0)
- Code (end) [https://github.com/Kritner-Blogs/OrleansGettingStarted/releases/tag/v0.63.0](https://github.com/Kritner-Blogs/OrleansGettingStarted/releases/tag/v0.63.0)
- Photo by [“ashin\_k\_suresh”](https://unsplash.com/photos/mkxTOAxqTTo) on [Unsplash](https://unsplash.com/).