Question

I have an Event Sourced system that has 3 micro services (simplified):

  • User management - Registering a user, change password etc
  • User account - manages debiting/crediting of the user account balance
  • Notifications - email notifications when balance changes

I have a requirement that we want to have Demo users that can use an app like any other user but we don't want to send any notifications to them.

Of course this is an example but you can see how other services can also have different behaviour based on this fact (demo or not).

I'd like to ask you what can be the best option to implement this. Of course it might be that i've got the micro services part wrong.

Potential Implementation 1

  1. When registering user i send demo flag within event so it looks like this:
UserRegistered(email, demo)
  1. I listen for this event in Notifications service and then decide to add the users without demo flag to it's internal store
  2. Then when Notifications service listens to AccountBalanceDebited(user, debit) event it just ignores the ones for user it does not have in internal store

Drawback is that i might end up adding more stuff to UserRegistered event

Potential Implementation 2

  1. When registering user i create either UserRegistered or DemoUserRegistered event
  2. I listen for UserRegistered event only in my Notifications service
  3. When Notifications service receives AccountBalanceDebited event i check whether we have user recorded (same as in Potential Implementation 1)

Drawback is that we have a lot of common behaviour for user and demo user so we need to listen for both events in most cases.

Potential Implementation 3

  1. When registering users i create UserRegistered(email) event and if this is demo user then i create UserDemoModeActivated(user_id)
  2. In Notifications service i listen to both events, on UserDemoModeActivated i just remove user record from internal store and proceed as in previous implementations

Implementation that i don't want to use

In Notifications service get the User entity (basically shared model) and check demo flag here.

Summary

The more i think of it the more i'm into 3rd solution and what i like about it is that it is more an addition than a change in the system.

This is my first approach to ES so i would be glad to get help with it.

Was it helpful?

Solution

When a user registers I assume they specifically opt-in to receive notifications due to legal reqiuirements such as the GDPR regulations in the EU. Therefore you could have two events during user account registration: UserRegistered and UserOptedInToReceiveNotifications.

The opt-in event would be consumed by the notification service to configure their account to receive emails. For demo users you wouldn’t create the second opt-in event, so these users won't receive emails. This ensures the notification service only deals with users who have specifically opted-in to receive notifications from you.

Another benefit of this approach is that a demo user could later choose to opt-in to notifications, via the existing UserOptedInToReceiveNotifications event, which would then kick-off the notification service as before.

OTHER TIPS

Duplicating all the users on the Notification service has got to be a mistake.

The approach I normally take is summed up as "Fat Events". Instead of sending:

UserRegistered
   Email

BalanceUpdated
   UserId
   NewBalance

I would send:

UserRegistered
   User : { id, email, address, category (demo)....}

BalanceUpdated
   User : { id, email, address, category (demo)....}
   BalanceChange : {id, date, amount, currency... }

This way services listening to the events can take a wide variety of actions without having to query other services or hold their own versions of data.

Your Notification service can simply check the properties of the User object contained in the message and apply its logic as to whether this user should be sent a message.

Alternatively. Notification settings such as "don't receive marketing emails" etc are clearly part of the Notification service. You could have the demo users set their settings on the notification service so as not to receive notifications.

I would go completely the opposite way with inter-microservice notifications - no payload at all, just type, event occurring and id.

Registered { "User", userId }

That way any listening service can make a decision "do I care about this event" and if so can ask the source service for the latest state. That way if either of the two communicating services are offline they can synch back up again easily.

However in terms of a demo or test user you really want as much of the system to be exactly the same regardless and only have the bit you absolutely need to work differently coded differently.

To my mind this means having a "do not send" list of emails in the Notifications service and give your demo users those email addresses.

Licensed under: CC-BY-SA with attribution
scroll top