Skip to content
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

Omit cancellation of transactional Monos in TransactionOperator #23562

Merged

Conversation

mp911de
Copy link
Member

@mp911de mp911de commented Sep 2, 2019

TransactionOperator.as(Mono) now no longer short-cuts via a Flux.next() but provides an implementation via Mono.usingWhen(…).
The short-cut previously issued a cancellation signal to the transactional Mono causing the transaction cleanup to happen without a handle for synchronization.

Using Mono.usingWhen(…) initiates transaction cleanup when the Mono completes eliminating the need for cancellation of the transactional Publisher.

This change does not fully fix #23304 but it softens its impact because TransactionalOperator.transactional(Mono) avoids cancellation.

/cc @michael-simons @simonbasle @smaldini


  • We should get feedback from Michael or someone from the reactor team prior to merging this PR.

TransactionOperator.as(Mono) now no longer short-cuts via a Flux.next() but provides an implementation via Mono.usingWhen(…).
The short-cut previously issued a cancellation signal to the transactional Mono causing the transaction cleanup to happen without a handle for synchronization.

Using Mono.usingWhen(…) initiates transaction cleanup when the Mono completes eliminating the need for cancellation of the transactional Publisher.

This change does not fully fix spring-projectsgh-23304 but it softens its impact because TransactionalOperator.transactional(Mono) avoids cancellation.
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Sep 2, 2019
// This will normally result in a target object being invoked.
// Need re-wrapping of ReactiveTransaction until we get hold of the exception
// through usingWhen.
return status.flatMap(it -> Mono.usingWhen(Mono.just(it), ignore -> mono,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wouldn't it be better to start from Mono.usingWhen?

return Mono.usingWhen(status, ignore -> mono, this.transactionManager::commit, ...)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We require the status value outside of usingWhen(…) (see rollbackOnException)

// Need re-wrapping of ReactiveTransaction until we get hold of the exception
// through usingWhen.
return status.flatMap(it -> Mono.usingWhen(Mono.just(it), ignore -> mono,
this.transactionManager::commit, s -> Mono.empty())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note that in case of cancellation, since no asyncCancel is defined here, it defaults to commit. Also, it feels weird that the error case is basically ignored

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit on cancel is what we want if just a subset of data is processed. In imperative code this compares to processing a subset of a result list.

The error case is ignored because errors are handled after the usingWhen operator. In case a pre-commit action fails, we want to issue a rollback. Committing a transaction consists of several activities of which the actual commit is just one of them. So if a commit fails, we still need to rollback,

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense, thanks for the explanations. nothing to add 👍

@mp911de
Copy link
Member Author

mp911de commented Sep 18, 2019

This PR is good to be merged from my side. It would be good to have this fix available in 5.2 GA.

@jhoeller jhoeller added in: data Issues in data modules (jdbc, orm, oxm, tx) type: enhancement A general enhancement and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Sep 18, 2019
@jhoeller jhoeller self-assigned this Sep 18, 2019
@jhoeller jhoeller added this to the 5.2 GA milestone Sep 18, 2019
@jhoeller jhoeller merged commit 393a81d into spring-projects:master Sep 20, 2019
jhoeller added a commit that referenced this pull request Sep 20, 2019
@mp911de mp911de deleted the transactional-operator-mono-fix branch September 21, 2019 17:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: data Issues in data modules (jdbc, orm, oxm, tx) type: enhancement A general enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

No means to synchronize when cancelling a TransactionalOperator Subscription (Publisher)
4 participants