CQRS and cache invalidation (while load balancing)

architectural-patternscqrsobject-oriented-design

I'm slowly trying to migrate our web application to use CQRS principals. In particular, I have separated "write" and "read" interfaces into commands and queries.

I have implemented a "reader" class that can read some data from the DB. I have also implemented a decorator for this reader that caches the data to avoid any unnecessary roundtrips to the DB. At the moment this decorator is caching per-request. I'd like to cache this data for a longer duration – eg for a sliding 5 minute window.

However, the problem is that a command that updates the data should invalidate the cache once the write occurs, and I'd like to capture that notion explicitly in our domain model.

Specifically, here is the "read" interface (c#):

public interface IRoleLister
{
    IList<DomainRole> Fetch(OtuIdentity otuIdentity);
    IList<DomainRole> FetchForAuthenticatedId(int userId);
}

And here is the write interface:

public interface ICanChangeDomainRoles
{
    void AddRoleToUser(int userId, DomainRole domainRole);
    void RemoveRoleFromUser(int userId, DomainRole domainRole);
}

I realize that some variant of the observer pattern would probably be applicable, but I'm not sure how to capture that in the domain model.

I also have identified another problem – namely cache key naming. In the IRoleLister I want to cache IList<DomainRole> by user (eg typeof(IList<DomainRole>) + ":userid" as the key) but in ICanChangeDomainRoles I don't know the key name. My thoughts are that the Observer should in someway be responsible for this. (Or perhaps some other interface? How do I capture that concept in my domain).

Finally, I realize that some form of distributed cache would help, but that seems like an implementation detail – I want to capture the invalidation/notification/observer concept in my domain model.

Any pointers would be appreciated

Best Answer

General case, I would expect caching to be a policy applied to the data and not an attribute of the data itself.

I this is a perfect candidate for aspect-oriented-programming (eg PostSharp) and/or inversion of control frameworks (eg Spring.Net).