if you want this guarantee:
“What I’m really after is when JobAssignedEvent is dispatched, from the application point of view, the job is really assigned. That means, if somebody invoke JobRepository#findAllUnassignedJob(), the job that I just assigned, will not be returned by that finder method.”
you’re really saying that you need full consistency. Full consistency means you cannot have either availability or partition tolerance. An still, you will never really have this guarantee 100%.
Even if you were to dispatch the event inside a single JVM in the same thread that handles the command, you cannot give this full guarantee. What if the request to the repo was done 1ms earlier? You would see the job as unassigned. 1ms later, and it might be assigned. By dispatching asynchronously, you add perhaps 10ms latency. A typical web request takes 500ms. So what’s 10ms extra staleness?
The only thing that I care about is within the same thread and the event is dispatched synchronously (They live in the same JVM).
I don’t care if the repository is invoked 1 ms earlier, but I do care when JobAssignedEvent is being handled, when 3rd party code invoke the job repository or directly query the db, the job is really assigned.
If this is not the case, there will be extra complexity as event handler can’t trust the persistence when handling the event.
We will be forced to create API that returns aggregate id in some use cases.
For example, The handler now has to:
List unassignedJobIds = jobRepository.findAllUnassignedPriorityOneJobIds(); // Necessary
unassignedJobIds.remove( event.getDomainId() ); // Performance penalty, creating many String instances, no paging.
int count = unassignedJobIds.size();
List topTenJobs = unassignedJobIds.subList( 0, 10 ); // Top ten jobs, but we only have the id not the object
List jobIds = jobRepository.findJobsById( topTenJobs ); // To get job instance
int count = jobRepository.countAllUnassignedPriorityOneJobs();
List jobs = jobRepository.findUnassignedJobIds( 10 ); // Guarantee that the assigned job will not be there.
We’ve been making ourselves believe that applications run in a fully consistent environment. They’re not! By the time you see data on screen, the application might have already moved along. So our unassigned job may have long been assigned by someone else.
Agree, but full consistent environment is not what I’m after. Not full consistent environment.
Only during event handling time that is handled synchronously that the application persistent behave as expected.
Of course, this only counts when you’re talking about a client invoking the repository. If it’s another event handler invoking the repository, you should ask yourself two questions. Is it really a bad thing if data is a bit stale. Most of the times, it isn’t. If the answer is yes, here is the second question: aren’t we talking about a single event listener accidentally split in 2?
We can’t make customization code to be in the same event listener (those codes are not written by us).
We have no control over these codes.
It’s a topic I focus on quite heavily in my workshop. It’s easier to explain face-to-face with a whiteboard