-
Notifications
You must be signed in to change notification settings - Fork 678
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ConcurrentModificationException for registerEvent in TransactionalEventListener #3116
Comments
It would be great if you could take the time to provide a complete minimal sample (something that we can unzip or git clone, build, and deploy) that reproduces the problem. |
The problem that happens here is that we obtain a collection of domain events. While processing domain events, the list of events is being modified. We could create a local copy of the domain events collection, call clear domain events first and then publish events to avoid leaving events unprocessed and clearing these. With clear-before-publish domain events would remain in the aggregate root waiting for the next processing round. Paging @odrotbohm for additional thoughts. |
To capture a bit more architectural context: the scenario in place here is problematic, as it manipulates the list of events during event handling. This in turn is caused by the transactional setup being incomplete. Using MongoDB in transactional mode needs explicit setup. With that missing, the This brings us to the root of the problem: an event must not contain references to mutable objects and the listener mutating that object. Registering additional events expands the issue into that new event being lost, as it would end up in the collection after its processing has started. Ideally, the event would only contain the identifier of the entity and the listener would look up the instance, initiate a state transition and complete the unit of work through a call to the repository. This would then cause the new event published properly. We can and should fix our collection processing to create a defensive copy for the iteration. What I am still unsure about is in how far we should still surface the issue of an event having been registered during the processing. There are essentially three options:
I think we could even go with 3 as this has never worked at all but would just surface in a not very obvious way. Still letting the approach fail but describing what's the problem in a better way sounds like the safest option to me. Feedback welcome! |
…hing. We now detect that the consumption of the events published during a persistence operation has produced new event instances that would go unpublished and raise an explaining exception. Previously such a scenario would've resulted in a ConcurrentModificationException. We primarily reject such a scenario as handling the additional event would extend our convenience mechanism over the publishing scope a direct 1:1 replacement with ApplicationEventPublisher would've achieved. Fixes GH-3116.
…hing. We now detect that the consumption of the events published during a persistence operation has produced new event instances that would go unpublished and raise an explaining exception. Previously such a scenario would've resulted in a ConcurrentModificationException. We primarily reject such a scenario as handling the additional event would extend our convenience mechanism over the publishing scope a direct 1:1 replacement with ApplicationEventPublisher would've achieved. Fixes GH-3116.
…hing. We now detect that the consumption of the events published during a persistence operation has produced new event instances that would go unpublished and raise an explaining exception. Previously such a scenario would've resulted in a ConcurrentModificationException. We primarily reject such a scenario as handling the additional event would extend our convenience mechanism over the publishing scope a direct 1:1 replacement with ApplicationEventPublisher would've achieved. Fixes GH-3116.
…hing. We now detect that the consumption of the events published during a persistence operation has produced new event instances that would go unpublished and raise an explaining exception. Previously such a scenario would've resulted in a ConcurrentModificationException. We primarily reject such a scenario as handling the additional event would extend our convenience mechanism over the publishing scope a direct 1:1 replacement with ApplicationEventPublisher would've achieved. Fixes GH-3116.
…hing. We now detect that the consumption of the events published during a persistence operation has produced new event instances that would go unpublished and raise an explaining exception. Previously such a scenario would've resulted in a ConcurrentModificationException. We primarily reject such a scenario as handling the additional event would extend our convenience mechanism over the publishing scope a direct 1:1 replacement with ApplicationEventPublisher would've achieved. Fixes GH-3116.
I have a DDD project where I expose a domain object which extends AbstractAggregateRoot:
Additionally there is a domain event listener in the same domain:
In the other domain there is an additional event listener:
Generally it uses the spring mongo implementation as the storage layer. If the service is called the following exception is thrown:
The text was updated successfully, but these errors were encountered: