causation or correlation id?

Here https://groups.google.com/d/msg/event-store/9dyhwgL2hVA/wFU62XSQtCYJ James Nugent say that when storing commands, events produced by it could have the command id as correlation id.

What would a causation id be then? To me it seems that a command causes an event to happen, and the event would then have a causation id that is the commandId.

I guess it’s up to me what I want to call it. But are there cases when you would use both, if so how?

Causation id correlation Id would set the events correlationid to the correlationid of the command

hm. That was actually a bit confusing :slight_smile: Causation id and? or? correlation id would set the events correlationid to the correlationid of the command?

So I assume the unique id of the command becomes the commands correlationid.

Here (Journey 7) there is also a SourceId. I guess that’s not a correlationId, but maybe a CausationId?

What is the causationid/sourceId for, when is it used?

The are both really simple patterns I have never quite understood why
they end up so misunderstood.

Let's say every message has 3 ids. 1 is its id. Another is correlation
the last it causation.

The rules are quite simple. If you are responding to a message, you
copy its correlation id as your correlation id, its message id is your
causation id.

This allows you to see an entire conversation (correlation id) or to
see what causes what (causation id).

Cheers,

Greg

What about messages that may need to correlate with more than one process? Or does that even exist?

Makes it perfectly clear. Thank you.

These aren't my patterns I just made up one day.

I tried to find a concise explaining of the pattern in a code design context, but there was mostly philosophical and statistical results. Not like searching for “Memento pattern”, which yields simple comprehensible summaries on first, and every consequent page. So, thanks again!

I have a DomainEvent base class that takes correlationId and causationId as constructor parameters.

So every event that I create has those two as first constructor parameters.

When persisting to eventstore the metadata is set with those.

The ctrs of the events can get rather long though.

An event ctr could look like this:

public OrderPlaced(Guid correlationId, Guid commandId, Guid orderId, Guid accountId, int actionCode)
: base(correlationId, commandId)

``

Where the causationId is of course the commandId.

Maybe this is a bit whacky? Haven’t seen anyone else design their events like this.

(Note: There is no need for order lines in this example, as an order of this sort always has one line only.)

Why are they part of the event as opposed to metadata associared with the event?

Good question.

Better use some Envelope instead, with the metadata, like in Conference demo.

I think it would result in this:

For the CommonDomain repository I would then get all envelopes when I get the events of the aggregate, (unless I unwrap them before saving to aggregate list of events). The body of the ES events to save, would then include that metadata. And of course, the same metadata would be put into the headers of the ES event to save. Would that redundancy be ok?

Why put in both body and metadata just put in metadata

I want to keep that metadata with the event throughout the entire domain. If I store them in the aggregate as envelopes, they become - with current implementation of CommonDomain eventstore repository - the body of the ES event, i.e. including the metadata. I can of course modify that repository implementation easily, and remove the update headers action from the parameter list, and instead extract the headers from the envelopes I get when calling aggregate.GetUncommitedEvents(), and also extract the clean event from the envelope, for saving in ES. (Still looking for how to use that update headers action passed as parameter anyway)

Maybe common domain is the problem.

You shouldnt put such things in event body they dont belong there

True.

I just realized btw that CommonDomain rep news up the eventId in the actual save method (var eventsToSave = newEvents.Select(e => ToEventData(Guid.****NewGuid(), e, commitHeaders))**.ToList();). I have up until now created the eventId with the event and stored it as it’s Id to have during its lifetime in the domain.

Also, I see now that my interpretation of correlationId might be off. Example from a ProcessManager in Conference demo:

if (envelope.CorrelationId != null)
{
if (string.CompareOrdinal(this.SeatReservationCommandId.ToString(), envelope.CorrelationId) != 0)
{
// skip this event
Trace.TraceWarning(“Seat reservation response for reservation id {0} does not match the expected correlation id.”, envelope.Body.ReservationId);
return;
}
}

``

Ok, so, even though it’s supposed to be a really simple pattern, I find myself wondering about it.

Seems like correlationId is sometimes the commandId. I have been suspecting this, without fully wrapping my head around it, and thinking that this id is always a Guid that is newed up at the start of a process, solely purposed to keep a line of correlation in the (figuratively speaking) “stream of events”. So, instead, CorrelationId could be any id of choice, it would depend on situation, and sometimes the correlation to something is best described with a command’s id.

I notice that I’d like to have a more strict rule for what a correlationId is composed of, so that the plethora of Guids used can be more easily categorized upon a quick glanze. Maybe that’s just a vane attempt to minimize the so abundant “it depends”…

CausationId though, is always the id of what ever directly caused the event/command.

Seems like correlationId is sometimes the commandId. I have been suspecting this, without fully wrapping my head around it, and thinking that this id is always a Guid that is newed up at the start of a process, solely purposed to keep a line of correlation in the (figuratively speaking) “stream of events”. So, instead, CorrelationId could be any id of choice, it would depend on situation, and sometimes the correlation to something is best described with a command’s id.

Why would the command not have a correlation I’d so you can just follow he same pattern as opposed to making many patterns?

Geez, that might be what’s confusing things so much. These are separate patterns?

You supposed to use correlation or causation id?

Causation id pattern would be like a linked list. Correlation id pattern would just group messages together, without order.

I thought they played well together though, having a single discriminator for group when projecting and also knowing the exact cause of a message.

(sidenote: updateHeaders is just for adding custom headers in code before calling save, code block would look like the dictionary creation in ToEventData method)

They are separate patterns and you hse both of them.

But just always copy correlation id correlation id is never commands message id

Allright, thanks.

That CQRS Journey example confused me about it.

Oh, also: This thing about handling envelopes with correlationId etc. separate from body (the actual domain event) leads to some conflicts.

In the Aggregate:

public void OpenAccount(Guid correlationId, Guid commandId, Guid accountId, Guid ownerId)
{
if (_opened) // or some other sort of validation
throw new InvalidOperationException(“Account already opened”);
ApplyEvent(new NewAccountOpened(correlationId, commandId, accountId, ownerId));
}

``

This is the pattern I’ve read is encouraged; Passing the members of the command as parameters.

Handled like this in abstract Aggregate class:

protected virtual void Apply(dynamic e) { }

public void ApplyEvent(object @event)
{
((dynamic)this).Apply(@event);
_uncommittedEvents.Add(@event);
this._version++;
}

``

With envelope, this pattern would not be followed, instead it would be like:

public void OpenAccount(Envelope envelope)
{
if (_opened) // or some other sort of validation
throw new InvalidOperationException(“Account already opened”);
var command = envelope.Body;
if (envelope.Body.GetType() == typeof(OpenNewAccount))
{
var @event = new NewAccountOpened(command.AccountId, command.OwnerId));
var eventEnvelope = Envelope.ForEvent(@event, envelope.CorrelationId, command.Id);
ApplyEvent(eventEnvelope);
}
else
throw new ArgumentException(“Wrong command type”);
}

``

and in the abstract aggregate base class:

public void ApplyEvent(Envelope envelope)
{
((dynamic)this).Apply(envelope.Body);
_uncommittedEvents.Add(envelope);
this._version++;
}

``

Then when saving to repository and calling the aggregate GetUncommittedEvents(), we would extract the body and the metadata separately from the envelope.

Is this how it is done then (more or less)?