Should deadlines be scheduled in a @CommandHandler or @EventSourcingHandler?

Should deadlines be scheduled in a @CommandHandler or @EventSourcingHandler?

For an aggregate:

  • When scheduling a deadline the deadlineManager.schedule(..) method returns a String deadlineId.
  • Given that we need to store that ID in the state of the aggregate (in case we need to cancel the deadline later) I assumed it would go in an @EventSourcingHandler (since we are changing the state of the aggregate).
  • However, placing it in an @EventSourcingHandler results in tests failing with: deadlineId has different value when sourcing events.
  • I believe this is expected behaviour because the test fixture runs the ‘given, when, then’ which is defined on it and then runs each event sourcing handler again and makes sure that the states match.
  • Since when the @EventSourcingHandler is run for the second time the scehdule(...) method is called again and a different deadlineId is stored as the state - this results in conflicting state between the first time the handlers are run and the second.
  • When using a @CommandHandler the test fails as well.

So my question is: what is the correct way to schedule a deadline and store the deadlineId for an aggregate?

For a saga:

  • I’m assuming it is best practice to schedule a deadline on a @SagaEventHandler. Everything works here without issue.

The short answer is, in command handler.

String schedule(Instant triggerDateTime, String deadlineName, Object messageOrPayload)

The result of this method is a deadlineId which you can include in the event that you will publish/apply in this same command handler, I presume. The event sourcing handler will eventually update the state of your aggregate and there you can store the deadlineId as an attribute as well.

Some other commands might result in canceling this particular deadline (you already have it in the aggregate state).

If the deadline expires (before it was canceled), the deadline will kick in:

@DeadlineHandler(deadlineName = MY_NAME)
void on(YourMessageOrPayloadType payload)

This deadline handler can be treated as a command handler, the diference is that the message is not a command but a deadline expiration message. This deadline handler can publish/apply event.

Best,
Ivan

2 Likes

Thanks Ivan - that makes a lot of sense.

Another related question. If we set a deadline, say for 15 mins, but 10 mins later we mark an aggregate as deleted - will the deadline still be triggered after 5 more mins?

Is it best practice to manually cancel deadlines in the command handler of the command which eventually causes the aggregate to be marked as deleted? Or should we not worry about that case?

1 Like

I believe that you have to (manually) cancel that deadline in the command handler. Most probably, it does not make much sense to have that deadline expires after you marked the aggregate deleted. Nevertheless, the deadline handler method will not be able to publish/apply any (domain) event for the aggregate that is marked as deleted.

1 Like