Open ylorph opened 4 years ago
A list of @skleanthous suggestions:
runtime requires the above for: 1 & 2 identify the message that needs to be acted upon 3 allows for parsing of different versions, in case of breaking changes 5 allows for checking for errors in distributed processes 8 for security and auth 9 for ~idempotency~ concurrency
The above can also be used for debugging: 5 can be used to get all messages that occurred from a single action. This is very useful as an index to causal queries. 4 & 6 allow building a causal chain of each command in a system 7-10 for context (along with data) The resource version is particularly useful when we can retrieve resource versions from our store (like in case of event sourcing), because having the causal chain available, we can replay the actual command on the precise state of the resource we want to inspect.
Other things that might be of interrest;
Per @skleanthous, 9 above should be about concurrency instead of idempotency.
I would domain qualify the message name - i.e Bank.Account.InterestAccrued in case different domains/entities use the same word to describe different events
@MerrionComputing The idea is that you put the domain name in metadata 2. Note that this doesn't necessarily have to be FQN = (metadata 2) + (metadata 1)
. Doing that has a risk of introducing breaking changes due to namespaces change due to refactoring if you then take advantage of this in the consumer, although this will very often be an acceptable tradeoff for productivity.
In some cases, I found it better to just use the domain, or domain and subdomain name, only in metdata 2 and leave the consumer explicitly map that to a message to get deserialized, although of course this is context-specific.
Regardless of what you put in metadata 2, I found splitting those two useful because it very often helps in debugging issues because it allows you to easily filter messages by name or by domain to enhance visibility.
Thinking about having a qualifier for the message as well:
just have a case where I have an event DeliveryAvailable
(It's assessments testing terminology ) , when some Delivery is published in the online assessment platform, but we use different online assessment platform.
So our integration has different DeliveryAvailable
event type in different modules
Since some of the details of the content of the message is different, parsing them is different as well.
I do need different message type & type name to facilitate processing
The other would be to go further in the abstraction of the assessment platform, but that is a step to far for us.
so DeliveryAvailable
in the Platform1 Module will have a name will be like Platform1.DeliveryAvailable
and in platform 2 something like Platform2.DeliveryAvailable
@ylorph That's an interesting point. A couple of thoughts on that:
Personally I see it like this:
As I said though, using something more in the message name isn't necessarily a bad idea, it comes with some tradeoffs. Splitting the service name is something that I recommend (as I said above) mostly to help with debugging, and helps me when I'm joining data to get context of a change.
we've been leaning into
recorded_at vs occurred_at
The other time they may vary widely is when "the system was down when we did this in the real world" or some other connectivity issue like "we did this 1000 miles from civilization and recorded it when we returned".
When doing this remember that you want two ways of reading things (possibly three, more on that below).
As-at and as-of
This can be done in a generic way and should apply to all event streams. Basically one is usually just read events forward (not occasionally connected might end up with two like the latter) ... the other is read events forward ... sort ... then return.
Once you have this you will be amazed how many problems fit pretty well into it.
https://twitter.com/SKleanthous/status/1197272391304523776
https://github.com/cloudevents/spec/blob/master/spec.md
See also
29
33