Skip to content

DRIVERS-2584 Errors handling in Convenient Transactions API #1475

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

Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,25 @@ MongoClient within the callback in order to execute operations within the
transaction. Per the `Driver Session`_ specification, ClientSessions should
already provide access to a client object.

Handling errors inside the callback
-----------------------------------

Drivers MUST document that the callback MUST NOT silently handle command errors
without allowing such errors to propagate. Command errors may abort the transaction
on the server, and an attempt to commit the transaction will be rejected with
``NoSuchTransaction`` error.

For example, ``DuplicateKeyError`` is an error that aborts a transaction on the
server. If the callback catches ``DuplicateKeyError`` and does not re-throw it,
the driver will attempt to commit the transaction. The server will reject the
commit attempt with ``NoSuchTransaction`` error. This error has the
Copy link
Member

Choose a reason for hiding this comment

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

@comandeo: @alcaeus will bring this up with you, but when talking about this earlier today we discussed whether "NoSuchTransaction" should trigger an early break from the withTransaction retry loop since it may indicate that the callback did something unexpected.

Copy link
Author

Choose a reason for hiding this comment

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

We discussed this with @alcaeus last week, and decided to keep the existing commit logic.

Rationale: when a driver receives NoSuchTransaction, we do not know what happened. This situation may be a result of some server side situation, like a fail-over. If this is the case, the driver should retry the transaction completely.

Since we cannot distinguish between situations where the callback did something unexpected and where something went wrong on the server, we should try to be safe, and retry. With the changes proposed in this PR we give users clear instructions to let the driver decide how to handle errors.

"TransientTransactionError" label and the driver will retry the commit. This
will result in an infinite loop.

Drivers MUST recommend that the callback re-throw command errors if they
need to be handled inside the callback. Drivers SHOULD also recommend using
Core Transaction API if a user wants to handle errors in a custom way.

Test Plan
=========

Expand Down Expand Up @@ -494,6 +513,7 @@ client-side operation timeout, withTransaction can continue to use the
Changes
=======

:2023-11-22: Document error handling inside the callback.
:2022-10-05: Remove spec front matter and reformat changelog.
:2022-01-19: withTransaction applies timeouts per the client-side operations
timeout specification.
Expand Down
9 changes: 9 additions & 0 deletions source/transactions/transactions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -982,6 +982,13 @@ label. For example:
continue
raise

Handling command errors
-----------------------

Drivers MUST document that command errors inside a transaction may abort
the transaction on the server. An attempt to commit such transaction will be
rejected with ``NoSuchTransaction`` error.

**Test Plan**
-------------

Expand Down Expand Up @@ -1407,6 +1414,8 @@ durable, which achieves the primary objective of avoiding duplicate commits.
**Changelog**
-------------

:2023-11-22: Specify that non-transient transaction errors abort the transaction
on the server.
:2022-10-05: Remove spec front matter and reformat changelog
:2022-01-25: Mention the additional case of a retryable handshake error
:2022-01-19: Deprecate maxCommitTimeMS in favor of timeoutMS.
Expand Down