Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Question: Do we need support for nested transaction? #5

Closed
codeliner opened this issue Aug 9, 2015 · 4 comments
Closed

Question: Do we need support for nested transaction? #5

codeliner opened this issue Aug 9, 2015 · 4 comments

Comments

@codeliner
Copy link
Member

Extracted from #4. Asked by @prolic.

@codeliner
Copy link
Member Author

@prolic prooph/event-store supports nested transactions since v4.0 but the adapter is not informed about it. The adapter only handles one transaction at the same time.

Reasons:
We added the nested transaction support to the event store because we had trouble with sagas handled in the same process as the causative command.
Because the TransactionManager of proophessor wants to start a new transaction for each command dispatched via the command bus, but when a second command was dispatched while transaction of the first command was not committed the event store threw an error.
Since 4.0 the event-store manages a transaction counter and only triggers adapter::commit when the last open transaction is going to be committed.

In an ideal world you would not dispatch two commands within the same transaction. Each command would be handled in its own transaction. In this case the events caused by the command are persisted on transaction commit and then they are published to interested listeners (like read model projectors or sagas).

But this set up adds complexity to the stack. What if the read model projection fails? The event was persisted and cannot be rolled back. Same for sagas: What happens if the second command fails?

In distributed systems you have to find answers to this questions and you need also solutions when you use different persistence mechanisms for your write and read model.

But as long as you use the same persistence layer for events, sagas and your read model you want to be able to rollback every stage when something breaks during a single process (http request/response cycle)

When using an RDBMS with transaction support this is relatively easy to achieve. Instead of publishing domain events after transaction commit you publish them before the transaction commit is passed to the low level database driver and therefor update the read model and/or trigger follow up commands in the same transaction.

For the mongo db adapter this would mean that the transaction_id needs to be added to the event metadata so that read model projectors or sagas can use the same transaction_id and perform similar clean ups on a eventstore.rollback.

Question is, do we want to support something like this?
The alternative would be to remove nested transaction support from the event store again and force users to find alternative ways to handle read model or saga errors.

Both concepts have their drawbacks and you need to understand a lot of internals.
That's the reason why we try to provide a basic set up with proophessor. So you can start simple (complexity is handled by proophessor behind the sense) but if you later need more freedom for your system set up you can customize the set up to meet your needs.

What do you think about all that 😄 ?

@prolic
Copy link
Member

prolic commented Aug 10, 2015

I think it's perhaps unneeded. A failing read model update could also trigger its own event. If the original event is correct, the system is able to run, the read model could not be up to date, but that is fine, as long as another process can try to re-update the read model later or handle the concrete failing event.

Examples:

  • User Registration not possible because of duplicate email address (possible from race conditions) -> New Event triggered UserRegisteredWithDuplicateEmailAddress, which can be handled appropriate.
  • User Registration not possible, because read model database is down -> New Event triggered ReadModelDatabaseDown, which can just get retried later.

Thoughts?

@codeliner
Copy link
Member Author

I like the approach. It reduces the complexity of transaction handling to allow only one transaction per command. No exceptions, no nested command dispatch. So users are forced to think about CQRS + DDD solutions for the problem.
For doctrine adapter the nested transaction support of the event-store worked fine but the mongo db adapter changes the game.
For now I would mark nested transactions as deprecated in the event-store (feature was not documented anyway) and remove it with prooph/event-store 6

@prolic
Copy link
Member

prolic commented Aug 10, 2015

Great! ;)

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants