5

Suppose you have a bounded context with ~30 business events and, for simplicity sake, the same number of commands like ChangeUserEmailCommand -> UserEmailChangedEvent initiated from a web UI. Processing a command may fail for the following main reasons (besides infrastructure failures of course):

  1. Validation issue (email uniqueness)
  2. Technical issue (optimistic concurrency version mismatch)

I'd be interested to provide the best user experience to the clients and display what went wrong.

What is the best practice to signal the failures?

  1. Would you create 30 more events like ChangeUserEmailFailedEvent? If not, what's your rule of thumb for which events to create a paired *FailedEvent?
  2. Is it a good idea to just have bool Success {get;set;} property in the existing events? It's probably not the best way when you need to signal more failure details than just an error message
  3. Would you create a single ConcurrencyFailedEvent for all concurrency issues adding a source command type as part of it's payload? Just to separate this kind of failure from business validation failures?

The commands are processed asynchronously (via a broker). The read storage is separated from the write storage. No event sourcing.

As for why would I need this I can think of the following:

  1. Detailed error message pushed back to a client via web sockets, for example
  2. Threat detection - reacting to an increased number of failed user registration which might be an attack
  3. Monitoring - displaying a number of failed orders on a dashboard, for example. If it's within a certain range I'd feel safe letting the support handle it. If it's above a certain number - I probably need to dig the logs.
UserControl
  • 159
  • 5

2 Answers2

2

Seems to me like you can get away with a single type

ErrorEvent
    EventId
    ErredEventId
    ErrorType
    Message

If you just have generic errors to deal with, but I would go further and remove Error events for UI stuff.

If the user is waiting to see if something erred you can pass the error back from the function they called and only write the event on success.

So, just EmailUpdated instead of EmailUpdateRequest EmailUpdateFailed EmailUpdated etc etc

You can see how going fully event driven can explode the number of types you need. If they are all internal to a thick client, then you have compile time checking to handle it all, but if you have to pass them over a distributed system it becomes ridiculous

Ewan
  • 83,178
1
  1. From your question I've understood ChangeUserEmailFailedEvent is a core part of your domain. So it should be always stored. The thing is that you can't predict how your business requirements will change so it's better to store your domain events just in case.
  2. Not sure what bool Processing {get;set;} means. In case it's not a domain concept - better omit it.
  3. Technical issues should not be stored in event logs as there are no business values in them. For tech-related stuff, you should maintain separate application log. (I mean like plain text files or Elastic APM logs or Logstash. I hope you get my point).