Commanded: how do you send a command to all of the aggregates?

Hi all

I am implementing a small SaaS with Commanded and one of the areas I am trying Commanded with is counting credits. Every month a free account is going to get some credits which are to be expired within a month if not used.

For tracking it I’ve got a CreditStore aggregate that has buckets of credits with attached expiration time. Adding/using credits is as simple as processing commands AddCredits/UseCredits, but expirations and adding more credits every month (or whatever plan’s timeframe chosen) are more difficult.

Sure I can check credits on demand or via explicit command. E.g. when somebody logs in, I could auto send CheckUpdateCredits and it should work. However, I’d like these monthly expirations/additions happen at roughly correct timing so that I could send notifications like “you’ve got more credits now, go use them” and also have ability to do nice admin reports on what’s the situation right now.

What would be the way to have every single aggregate in the system process some command regularly?

Exact timing is not important, so it’s fine if it happens within an hour or so from the ideal moment. The best I was able to invent is forcing every aggregate have projection with own id and closest expiration time, then some cron-like utility every X minutes to check who needs to be checked and then send lots of CheckUpdateCredits commands to these.

Is this how periodic checks of all aggregates are usually done? Or is these some other [easy] way to schedule processing of all aggregates in the system once in a while?

Hi,

I solved a problem with expiration time of marketplace offers - in a commanded system - by combining Oban scheduled jobs and single commands for every aggregate.

So, whenever the property expiration time changes, I create a new Oban job and maybe delete the old one directly from the execute callback.

I don’t know how to do it with Commanded, but what I would do is to schedule a command CheckCredit in the near future (one hour? one day? at the end of the month?)
The command will be fired and the handler could check if the credit is ok.

Does Commanded support scheduled Commands?

I think there are two questions here. One around modeling and the other around infrastructure.

From a functional standpoint the modeling shouldn‘t care for when certain commands come in or who/what issued it. The aggregate should hold or receive all the information it needs and not care about passage of time in between commands (which would be an side effect).

Then there‘s the question about scheduling commands not triggered by a human - and aligning it with real life continuation of time. This can be done many ways from OTP timers to quantum to oban to external tools. The trickiest bit it how do deal with your system not being up at those scheduled times, though in the end it‘s often not different to how an external user would deal with your system being down - retries and eventual consistancy.

Indeed my aggregates hold all the information it needs for knowing amount of credits at any given moment of time (as we can always calculate how many monthly additions/expirations happened at any given moment of time).

I have modeled the aggregate so that it contains of credit buckets with different expiration dates. Some buckets are bulk of credits added forever, some buckets are the results of monthly additions (so if you are on a monthly plan, every month you get a fresh bucket of credits which will expire in a month).

With this architecture over time you’d get more and more buckets (most of which will be empty soon) and… after this message thread I am not sure if it was that smart choice after all :slight_smile:

I suppose my modeling choices were guided too much by the wish to have nice lines in the user account for credits being added each month and then spent from exactly that bucket. Yet it probably should be a purely projection business somehow.

Dynamic projections
I’ll now go and rethink of how I could achieve the same goal with more static aggregates. Then probably the proper question to ask is: how to do time-dependent projections?

My aggregates do include all the information needed for calculating the amount of credits at any given moment of time (history of plans, history of user spendings), but how сould projections show amount of credits at exactly the current moment (or around it, doesn’t have to be super-precise moment of time)? I wouldn’t like to just dump aggregate formula ingredients to projection for the client code to perform the calculations.

Are there any good books on Commanded? There was one on leanpub, but the author didn’t finish the book. :frowning:

I’d argue that this is the wrong way to go about this. A projection is a materialized view of the state declared by all the events in the system combined. Events in commanded are emitted from the aggregate command handlers, which in turn are triggered by commands.

Therefore the only way your system would advance its state is by receiving commands. It doesn’t matter is the command is triggered through time based scheduling (your system) or a user (not controlled/controllable by yourself).

You can either keep the time component outside the system and trigger the necessary commands out of band from some scheduling solution or if you really want you could take on the additional complexity of modeling time within commanded as well, where you’d just advance the state of a ClockAggregate (again scheduled with commands, but only for a single aggregate) and then e.g. use ProcessManagers to turn clock advancements into other events depending on time to be triggered like ExpireCredit.

Certainly simple ready-to-use projections would be good to have - that is after all pretty much my main motivation for Commanded in the first place.

Hmm, then maybe idea to have time dependent state in the aggregate is not too bad after all. In essence there would be some duplication in the aggregate:

  1. “Formula” components that is basically current plan (and a history of plan starts-stops) + history of credit usage => should be mathematically enough to calculate amount of credits for any given “now” moment
  2. “Cached” value (maybe sliced to buckets or whatever I find convenient) for some exact moment of time → these will be most useful for creating-updating projections.

And then once in a while and on demand I can issue CheckUpdateCredits command that would update that cached state for the current situation.

Is this amount of duplication-caching inside an aggregate likely to be okay?

Then I guess I just need to figure a way to periodically send these CheckUpdateCredits commands to all aggregates in the system. Scheduling itself could be Oban or Rihanna or something like this and for getting list of all accounts in the system (so I knew who to send command to) I probably can just make sure that all accounts have some projection with their ID included.

Tbh I’d start by embracing the eventual consistancy and not do any calculations or caching to start with. Build the system to work. Then if you really cannot keep your system current enough for your needs start adding calculations and/or caches to bridge just the gap between time based effects being theoretically in effect and your system reflecting those.

In commanded (and EventSourcing) you would use a ProcessManager for this.

A process manager is responsible for coordinating one or more aggregates. It handles events and dispatches commands in response.

I haven’t read the full discussion yet, but this seems the way you should solve your problem.

Every month you would emit an event like CreditExpiryCheckRequested. The process manager listens to that event and the process manager sends commands.

Having said, think about your domain model, is this the best way to do this kind of thing? Are your aggregates modelled correctly, what are other options?