Ответ 1
Любая информация, которую агрегат требует для принятия бизнес-решений, должна храниться как часть совокупного состояния. Таким образом, когда получена команда для внесения денег на клиентскую учетную запись, у вас должно быть уже текущее состояние/обновление для этого клиента, который может содержать текущий баланс для каждой из своих учетных записей.
Я бы также предположил, что агрегат никогда не должен переходить к модели чтения, чтобы извлекать информацию. В зависимости от того, чего вы пытаетесь достичь, вы можете обогатить команду дополнительными деталями из модели чтения (где состояние не является критическим), но сам агрегат должен извлекать из него собственное известное состояние.
ИЗМЕНИТЬ
После повторного чтения вопроса я понимаю, что вы говорите о состоянии отслеживания в нескольких агрегатах. Это относится к царству саги. Вы можете создать сагу, которая отслеживает порог, который должен находиться в верхних 10%. Таким образом, всякий раз, когда клиент делает депозит, сага может отслеживать, где это размещает их в рейтинге. Если этот клиент пересекает потоки, вы можете опубликовать команду из саги, чтобы указать, что они соответствуют требуемым критериям.
В вашем случае ваша сага может отслеживать общую сумму всех депозитов, поэтому при внесении депозита можно принять решение о том, находится ли клиент сейчас в топ-10%. Другие вопросы, которые вы можете задать себе... если клиент внесет сумму в размере $X, и сразу же увеличит ширину $Y, чтобы вернуться обратно под thashashold; что должно произойти? Etc.
Очень грубые методы обработки агрегата/саги...
public class Client : Aggregate
{
public void Handle(DepositMoney command)
{
// What if the account is not known? Has insufficient funds? Is locked? etc...
// Track the minimum amount of state required to make whatever choice is required.
var account = State.Accounts[command.AccountId];
// Balance here would reflect a point in time, and should not be directly persisted to the read model;
// use an atomic update to increment the balance for the read-model in your denormalizer.
Raise(new MoneyDeposited { Amount = command.Amount, Balance = account.Balance + command.Amount });
}
public void Handle(ElevateClientStatus command)
{
// you are now a VIP... raise event to update state accordingly...
}
}
public class TopClientSaga : Saga
{
public void Handle(MoneyDeposited e)
{
// Increment the total deposits... sagas need to be thread-safe (i.e., locked while state is changing).
State.TotalDeposits += e.Amount;
//TODO: Check if client is already a VIP; if yes, nothing needs to happen...
// Depositing money itself changes the 10% threshold; what happens to clients that are no longer in the top 10%?
if (e.Balance > State.TotalDeposits * 0.10)
{
// you are a top 10% client... publish some command to do whatever needs to be done.
Publish(new ElevateClientStatus { ClientId = e.ClientId, ... });
}
}
// handle withdrawls, money tranfers etc?
}