Notifiying the client about Saga failure

Hi Allard,

I have a question about how to notify the client about a failure when
using a Saga (I'm aware that I could do the same with "eventual
consistency" by simply doing a query in command handler of step "2.").

In the "Meta CQRS" application we have two aggregates: "Aggregate" and
"Operation" ("Operation" is not modeled as a child entity of
"Aggregate" because it's referenced by other third party aggregates).

RULES:

1) An "Operation" belongs to exactly one "Aggregate" (modeled by a
"parentAggregateId" inside the operation)

2) The name of an operation is unique inside the aggregate (modeled by
a list of operation names inside the aggregate)

SAGA:

1. [CLIENT]
CreateOperationCommand(operationId, operationName, parentAggregateId)

2. [COMMAND HANDLER]
handleCreateOperationCommand(..)
new Operation(operationId, operationName, parentAggregateId)
// Does NOT store "parentAggregateId" yet!
=> OperationCreatedEvent(operationId, operationName,
parentAggregateId)

3. [SAGA]
handleOperationCreatedEvent(..)
AddOperationCommand(parentAggregateId, operationName, operationId)

4. [COMMAND HANDLER]
handleAddOperationCommand(..)
parentAggregate.addOperation(operationName, operationId)
a) OK
   => OperationAddedEvent(parentAggregateId, operationName,
operationId)
b) DuplicateException
   => AddOperationFailedEvent(parentAggregateId, operationName,
operationId)

5. [SAGA]
handleOperationAddedEvent(..)
AssignAggregateCommand(operationId, parentAggregateId)

6. [COMMAND HANDLER]
handleAssignAggregateCommand(..)
operation.assign(parentAggregateId)
=> AggregateAssignedEvent(operationId, parentAggregateId)

7. [COMMAND HANDLER]
handleAddOperationFailedEvent(..)
operation.delete()
=> OperationDeletedEvent(operationId)

How do I notify the client about this failure? (The client received an
"OK" in step "1.")

Cheers,
Michael

Hi Michael,

thats a very interesting question, which usually takes quite some q&a + discussion to answer correctly. Since you are using a saga, I suppose you decided that atomic transactions aren’t needed. I also assume that failures are quite rare in this case.

One option is to have the Saga generate an ApplicationEvent that indicates something is out of the ordinary. A notification could be stored in a database, streamed to the user interface or sent to an admin by email. That is, of course, if the Saga is not able to resolve the problem automatically.

But while reading your process, it really sounds to me that you want a certain level of atomicity in the process. In other words, you might have been cutting an aggregate in two here. Having remote references doesn’t have to be a problem. As long as they say “the … operation of the … aggregate”.

I am sorry for not answering your question clearly, but I hope I managed to give you some food for thought. If not, let’s keep the discussion going…

Cheers,

Allard

Hi Allard,

But while reading your process, it really sounds to me that you want a
certain level of atomicity in the process. In other words, you might have
been cutting an aggregate in two here. Having remote references doesn't have
to be a problem. As long as they say "the ... operation of the ...
aggregate".

Sound like this would soften Eric Evans rule: "The root is the only
member of the AGGREGATE that outside objects are allowed to hold
references to..." - But this may be OK as it's not a Java object
reference to the inner object (the operation). As you said it is a
composite key: "Aggregate[UUID]+OperationName[String]".

But thinking about the problem it seems indeed more natural that the
"Aggregate" object contains an "Operation" member - Wheee... Talking
about "Meta" things sounds sometimes weird... :wink:

Cheers,
Michael