Projections to replace in code stateful eventhandlers?

Hi, in my DDD/CQRS/ES app, I have several event handlers that listen to several streams and update a specific readstore view each. Some of those handlers are what I would call stateless, in that they can just update the readstore view with the data that they have and all is well. But a handful collect state which they use to enhance the event as it comes through. So for instance I have a TrainerPayments handler. the TrainerPaid event comes through with
{

trainerId: 123,

appointments:[

appointmentId:123,

]

}

maybe a bit more but the read view wants to see

Bobby Jones was Paid for Appointments:

1/1/2018 | Bubba Smith | 7:30 AM | Down Town Location

etc…

so my handler listens to all relevant appointment events and builds up a list of appointments, a list of clients and builds up a list of clients, locations so on and so forth. The state is persisted in the db or a cache. So then when a TrainerPaid event comes in I can create an entry in the readstore with all the data that the frontend wants to see.
This is basic event enhancing. Some do it before the event is fired by querying the readstore, I do it on the other end so I don’t have to deal with race conditions etc.
So I was wondering if this would be a possible candidate for a projection? Projections can maintain state. It seems like this would work in the same way. The upside being that I wouldn’t have to manage keeping my eventhandler state persisted.
Does this sound plausible?

Hi Ralf,

We do something similar, but use a partition state (maybe partitioned on trainerId)

We still use the read model for scenarios where we might want to query multiple records (imagine trying to do this over multiple partitions, or even one big state object holding it)

For example, if we wanted to return a paginated list of Trainer records, it would almost certainly be read model, but if we wanted an update approach of getting access to the trainer (and all the appointments) then a partition on this would be pretty useful.

Hi Steven,
I’m not sure I follow, re: partitions. Are you saying that you use a partition as a stream? or a projection? How does this get you an aggregated state?

Thanks,

R

Hi Ralf,

Something like this:

fromStreams(’$ce-UserAggregate’,’$ce-AccountAggregate’) //listens to any streams related to your account
.partitionBy(function (e) {
return “UserAccounts-” + e.data.userId.replace(/-/gi, “”);
})
.when({
$init: function (s, e) {
return {
accounts: {}
}
},

    'AccountCreatedEvent': initialiseAccount,
    'BalanceUpdatedEvent': updateBalance
   })

This lets us build up a"live" balance fairly easily, and from out server code we simply read the partition state.

Hope this helps

``

Thanks Steven,
I guess I wasn’t/am not familiar with the .partionBy function, does that create an actual logical partition? Seems like that would only be necessary for very large streams. Is that right?

thanks,

R

Yeah, it creates a logical partition. This works well for us keeping an update to balance, but don’t see it necessarily related to stream size.

Hope you get some inspiration from it lol

Steven