Skip to content

4. Readmodels

Simon Heiss edited this page Aug 11, 2019 · 4 revisions

Microwave supports distributed systems and you can subscribe to events from any service with just implementing an interface. Microwave will get the events, put them in the handling classes and saves the location where you left of, in case a service is unavailable or an error occurs during the event handling on the client side.

ReadModels and Querries

Microwave has ReadModels and Querries that can be used to create a querry service that is independent from the write side and therefore can be run in parallel. There are two main differences between Querries and ReadModels: ReadModels can be retrieved with an Identity and Querries are retrieved by their classname. For example you can have a ReadModel that represents a UserReadModel that can be retrieved by the UserId and a Querry could be the Top 10 Most Active Users in the Domain.

Querries

To add a Querry, inherit from Querry and implement the IHandle Interface to register the Querry to the specific DomainEvent. A Querry could look like this:

public class UserCounterQuerry : Querry, IHandle<UserCreatedEvent>
{
    public int Count { get; private set; }

    public void Handle(UserCreatedEvent domainEvent)
    {
        Count++;
    }
}

Readmodels

To add a ReadModel inherit from ReadModel<T> where T is the type of DomainEvent where the Readmodel is being created. After the creation Microwave tracks the ReadModel and updates it when new events emerge. Also implement IHandle accordingly. The Readmodel also has a version that is being updated alongside with the write side, so you can call the write side with the eventual consistent version. If you want to version to be passed in the function, to save it directly in the readmodel or do something else with it, implement the IHandleVersioned interface and Microwave will also pass the version of the domain event. The version is also updated, when the event is not processed by the ReadModel. For example the entity could create another event UserDeletedEvent but as there is no IHandle implemented, the event get skipped but the version will still be updated. A ReadModel could look like this:

public class UserReadModel : ReadModel<UserCreatedEvent>,
    IHandle<UserCreatedEvent>,
    IHandleVersioned<UserChangedNameEvent>
{
    public void Handle(UserCreatedEvent domainEvent)
    {
        Id = domainEvent.EntityId;
    }

    public void Apply(UserChangedNameEvent domainEvent, long version)
    {
        Name = domainEvent.Name;
        InnerVersion = version;
    }

    public Identity Id { get; private set; }
    public string Name { get; private set; }
    public long InnerVersion { get; private set; }
}

Loading Querries and Readmodels

To load the Querries and ReadModels there is a IReadModelRepository that offer functionality to load and update Querries/Readmodels. Inject it and you can use it to update Querries or Readmodels inside a IHandleAsync by yourself, if you need to.

Cron Timing of Updates

Microwave triggers an update for readmodels/querries every second by default. If you have readmodels that do not have to be updated frequently and if you want to save traffic, you can define the update cycle with the IPollingInterval in the startup class. The class accepts a string wich represents a cron notation or a integer which triggers the job every n full seconds. The T is the class that implements the IHandle or IHandleAsync interface. A registration could look like this:

public void ConfigureServices(IServiceCollection services)
{
    ...
    
    services.AddMicrowave(config =>
    {
        config.PollingIntervals.Add(new PollingInterval<MyAsyncHandler>("* * * * 2")); // Update every two minutes
        config.PollingIntervals.Add(new PollingInterval<MyReadModel1>(20));            // Update every 20 seconds
    });
}