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):
- Validation issue (email uniqueness)
- 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?
- Would you create 30 more events like
ChangeUserEmailFailedEvent
? If not, what's your rule of thumb for which events to create a paired*FailedEvent
? - 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 - 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:
- Detailed error message pushed back to a client via web sockets, for example
- Threat detection - reacting to an increased number of failed user registration which might be an attack
- 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.
-
1As usual: It depends. What are your requirements? Please add more details to your question.helb– helb2020年02月24日 11:43:59 +00:00Commented Feb 24, 2020 at 11:43
-
Thanks, updated as much as I could. Imo, these requirements are rarely part of what engineering teams get as an input. I hope to hear some practical advice from whoever built real life systems with EDA because there is not much information on the subject in those dozens of videos/article I've read so far.UserControl– UserControl2020年02月24日 12:06:28 +00:00Commented Feb 24, 2020 at 12:06
-
1There are also non-formal requirements to consider. It seems that you want to notify event listeners when an action failed (wich would normally lead to an event). Why do you want to achieve this? Is it important? What should event listeners do when they are notified about a failed action?helb– helb2020年02月24日 12:51:26 +00:00Commented Feb 24, 2020 at 12:51
-
How are your commands processed? Synchronously or asynchronously? Do you have eventual consistency implemented?Andy– Andy2020年02月24日 12:58:46 +00:00Commented Feb 24, 2020 at 12:58
-
@Andy, Thanks for clarifying! Added extra details.UserControl– UserControl2020年02月24日 13:08:08 +00:00Commented Feb 24, 2020 at 13:08
2 Answers 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
-
I think it boils down to: Can the user recover from the error? If no, all they need is a message saying "an error occurred". They can't do anything anyway, so alert and tell them to try again later. If they can recover then you need the message and other data to determine what to do next as indicated here.Jon Raynor– Jon Raynor2020年02月24日 19:40:38 +00:00Commented Feb 24, 2020 at 19:40
-
Id say its more, can the system self recover. If there is a human they can read the mesage. If its a computer they need structured dataEwan– Ewan2020年02月24日 21:18:19 +00:00Commented Feb 24, 2020 at 21:18
- 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. - Not sure what
bool Processing {get;set;}
means. In case it's not a domain concept - better omit it. - 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).
-
Thanks. What do you mean by "it should be always stored"? I'm not using Event Sourcing. As for #2 - it was a typo, my bad (should be
Success
, renamed the property).UserControl– UserControl2020年02月24日 17:39:25 +00:00Commented Feb 24, 2020 at 17:39 -
1"I'm not using Event Sourcing" - my bad, missed that. Still, I'd stick to firing all those events that are used by business domain. Regarding Success property, I think it's better to pass some sort of EventArgs class with all info needed to handle the event correctlyBohdan Stupak– Bohdan Stupak2020年02月25日 10:11:14 +00:00Commented Feb 25, 2020 at 10:11
Explore related questions
See similar questions with these tags.