[DRIVERS-2584] Infinite loop in generic transactional provider due to dup keys Created: 03/Mar/23  Updated: 12/Dec/23

Status: Implementing
Project: Drivers
Component/s: Transactions
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Raman Gupta Assignee: Dmitry Rybakov
Resolution: Unresolved Votes: 0
Labels: alex+, james+, rachelle+
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Depends
is depended on by NODE-5659 Driver retries a transaction operatio... Blocked
Issue split
split to CDRIVER-4755 Infinite loop in generic transactiona... Backlog
split to CSHARP-4828 Infinite loop in generic transactiona... Backlog
split to CXX-2778 Infinite loop in generic transactiona... Backlog
split to GODRIVER-3033 Infinite loop in generic transactiona... Backlog
split to NODE-5721 Infinite loop in generic transactiona... Backlog
split to RUBY-3341 Infinite loop in generic transactiona... Closed
split to RUST-1788 Infinite loop in generic transactiona... Closed
split to MOTOR-1203 Infinite loop in generic transactiona... Backlog
split to PHPLIB-1298 Infinite loop in generic transactiona... Backlog
split to PYTHON-4019 Infinite loop in generic transactiona... Scheduled
split to JAVA-5227 Infinite loop in generic transactiona... Backlog
Driver Changes: Needed
Quarter: FY24Q4
Downstream Changes Summary:

Summary of necessary driver changes

  • Document that errors should not be silently handled when using convenient transaction api
  • Document that command errors may abort transaction on the server

Commits that describes docs changes
(and/or refer to an existing language POC if needed)

Case:
Engineering Lead: Andreas Braun Andreas Braun
Start date:
Driver Compliance:
Key Status/Resolution FixVersion
CDRIVER-4755 Backlog
CXX-2778 Backlog
CSHARP-4828 Backlog
GODRIVER-3033 Backlog 2.1.0
JAVA-5227 Backlog
NODE-5721 Backlog
MOTOR-1203 Backlog 3.4
PYTHON-4019 Scheduled 4.7
PHPLIB-1298 Backlog
RUBY-3341 Fixed 2.19.3
RUST-1788 Fixed 2.8.0

 Description   

This is a follow-up to SERVER-34059.

This can cause an infinite loop when implementing a generic transactional callback.

Say my client code does something like this in pseudo-code:

inTransaction
  execute insert with duplicate key
  catch exception, return something

The client has caught the error and returned something rather than re-throwing. However, the `inTransaction` implementation does not know that the transaction has been aborted due to SERVER-34059 (see also https://jira.mongodb.org/browse/DOCS-11493, and so attempts to commit.

The commit call now throws a `MongoCommandException` with error 251 (`NoSuchTransaction`). This exception also has the `TransientTransactionError` label. Therefore, per documentation (https://www.mongodb.com/docs/manual/core/transactions-in-applications/), the `inTransaction` implementation should retry the entire transaction.

The client code then attempts the same insert resulting in dup key again, and now we have an infinite loop.

I understand that technical issues prevent the server from not aborting the transaction on the dup key error. However, the inTransaction implementation needs some way to differentiate this case from other transient errors, allowing it to ignore the error at commit time instead of retrying. We could ignore all NoSuchTransaction errors at commit time, but that feels like it may cause other unexpected issues.

Perhaps the error could carry an additional label? Something like "TransactionAbortedDueToDupKey" or maybe "TransactionAbortedDueToFailingOperation" or something like that?



 Comments   
Comment by Githook User [ 05/Dec/23 ]

Author:

{'name': 'Dmitry Rybakov', 'email': 'dmitry.rybakov@mongodb.com', 'username': 'comandeo'}

Message: DRIVERS-2584 Errors handling in Convenient Transactions API (#1475)

Co-authored-by: Andreas Braun <alcaeus@users.noreply.github.com>
Co-authored-by: Jeremy Mikola <jmikola@gmail.com>
Branch: master
https://github.com/mongodb/specifications/commit/13117d601fb6ea177e485880175b5be1651a7e46

Comment by Durran Jordan [ 31/Jul/23 ]

Looks like the solution here is for the driver to apply some custom label in this case and then not to retry the transaction in that specific scenario.

Comment by Durran Jordan [ 11/Apr/23 ]

chris.kelly@mongodb.com could the server add the proposed label to the error for any case where the driver must not retry the transaction? Maybe something like "NonRetryableTransactionError" or something similar? Or is the expectation here that the driver would apply the label in this specific case?

Comment by Chris Kelly [ 06/Mar/23 ]

Hi rocketraman@gmail.com,

Thanks for the detailed report! I'll pass this along to the relevant team to look into this further.

Christopher

Generated at Thu Feb 08 08:25:56 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.