From e54b4dedbbd16c64d1f1e898638b4b02a28b38b6 Mon Sep 17 00:00:00 2001 From: rustagir Date: Tue, 12 Nov 2024 10:19:51 -0500 Subject: [PATCH 01/10] DOCSP-42774: transactions --- source/includes/interact-data/transaction.rb | 129 +++++++++ source/interact-data.txt | 4 + source/interact-data/transaction.txt | 283 +++++++++++++++++++ 3 files changed, 416 insertions(+) create mode 100644 source/includes/interact-data/transaction.rb create mode 100644 source/interact-data/transaction.txt diff --git a/source/includes/interact-data/transaction.rb b/source/includes/interact-data/transaction.rb new file mode 100644 index 00000000..447bfc6e --- /dev/null +++ b/source/includes/interact-data/transaction.rb @@ -0,0 +1,129 @@ +# start-example-models +class Book + include Mongoid::Document + + field :title, type: String + field :author, type: String + field :length, type: Integer +end + +class Film + include Mongoid::Document + + field :title, type: String + field :year, type: Integer +end +# end-example-models + +# start-txn-operations +# Starts a transaction from the model class +Book.transaction do + Book.create(title: 'Covert Joy', author: 'Clarice Lispector') + Film.create(title: 'Nostalgia', year: 1983) +end + +# Starts a transaction from an instance of Book +book = Book.create(title: 'Sula', author: 'Toni Morrison') +book.transaction do + book.length = 192 + book.save! +end + +# Starts a transaction from the Mongoid instance +Mongoid.transaction do + book.destroy +end +# end-txn-operations + +# start-different-clients +# Defines a class by using the :default client +class Post + include Mongoid::Document +end + +# Defines a class by using the :encrypted_client +class User + include Mongoid::Document + + store_in client: :encrypted_client +end + +# Starts a transaction on the :encrypted_client +User.transaction do + # Uses the same client, so the operation is in the transaction + User.create! + # Uses a different client, so it is *not* in the transaction + Post.create! +end +# end-different-clients + +# start-lower-lvl-api +# Starts a session from the model class +Book.with_session do |session| + # Starts the transaction in the session + session.start_transaction +end + +book = Book.new +# Starts a session from an instance of Book +book.with_session do |session| + # Starts the transaction in the session + session.start_transaction +end +# end-lower-lvl-api + +# start-commit-abort +Book.with_session do |session| + session.commit_transaction +end + +Book.with_session do |session| + session.abort_transaction +end +# end-commit-abort + +# start-commit-retry +begin + session.commit_transaction +rescue Mongo::Error => e + if e.label?(Mongo::Error::UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL) + retry + else + raise + end +end +# end-commit-retry + +# start-other-client +# Specifies that the operation should use the "other" client instead of +# the default client +User.with(client: :other) do + Post.with(client: :other) do + Post.with_session do |session| + session.start_transaction + Post.create! + Post.create! + User.create! + session.commit_transaction + end + end +end +# end-other-client + +# start-model-session +Book.with_session(causal_consistency: true) do + Book.create! + book = Person.first + book.title = "Swann's Way" + book.save +end +# end-model-session + +# start-instance-session +book = Book.new +book.with_session(causal_consistency: true) do + book.title = 'Catch-22' + book.save + book.sellers << Shop.create! +end +# end-instance-session \ No newline at end of file diff --git a/source/interact-data.txt b/source/interact-data.txt index 442d855e..aa21c568 100644 --- a/source/interact-data.txt +++ b/source/interact-data.txt @@ -16,6 +16,7 @@ Interact with Data /interact-data/specify-query /interact-data/modify-results + /interact-data/transaction In this section, you can learn how to use {+odm+} to interact with your MongoDB data. @@ -25,3 +26,6 @@ MongoDB data. - :ref:`mongoid-data-modify-results`: Learn how to modify the way that {+odm+} returns results from queries. + +- :ref:`mongoid-data-txn`: Learn how to perform multi-document + transactions to make atomic data changes. \ No newline at end of file diff --git a/source/interact-data/transaction.txt b/source/interact-data/transaction.txt new file mode 100644 index 00000000..dca91cc3 --- /dev/null +++ b/source/interact-data/transaction.txt @@ -0,0 +1,283 @@ +.. _mongoid-data-txn: + +========================= +Transactions and Sessions +========================= + +.. facet:: + :name: genre + :values: reference + +.. meta:: + :keywords: code example, ACID compliance, multi-document, ruby odm + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +Overview +-------- + +In this guide, you can learn how to use {+odm+} to perform +**transactions**. Transactions allow you to perform a series of operations +that change data only if the entire transaction is committed. +If any operation in the transaction does not succeed, the driver stops the +transaction and discards all data changes before they ever become +visible. This feature is called **atomicity**. + +In MongoDB, transactions run within logical **sessions**. A +session is a grouping of related read or write operations that you +want to run sequentially. Sessions enable causal consistency for a group +of operations and allow you to run operations in an **ACID-compliant** +transaction that meets an expectation of atomicity, consistency, +isolation, and durability. MongoDB guarantees that the data involved in +your transaction operations remains consistent, even if the operations +encounter unexpected errors. + +In {+odm+}, you can perform transactions by using the following APIs: + +- :ref:`mongoid-txn-high-level`: {+odm+} manages the life cycle of the + transaction. You can use this API in {+odm+} v9.0 and later. + +- :ref:`mongoid-txn-low-level`: You must manage the life cycle of the + transaction. You can use this API in {+odm+} v6.4 and later. + +The :ref:`mongoid-txn-session` section describes how to make changes to +your data from within a session without performing a transaction. + +.. _mongoid-txn-high-level: + +Higher Level API +---------------- + +You can start a transaction by calling the ``transaction()`` method on +an instance of a model, on the model class, or on a ``{+odm+}`` module. + +When you call the ``transaction()`` method, {+odm+} performs the +following tasks: + +1. Creates a session on the client. + +#. Starts a transaction on the session. + +#. Performs the specified data changes. + +#. Commits the transaction if no errors occur or ends the transaction if + there is an error. See the :ref:`` section to learn more an + +#. Closes the session. + +If your transaction is committed, {+odm+} calls any ``after_commit`` +callbacks for all objects modified inside the transaction. If there is +an error and the transaction is rolled back, {+odm+} calls any +``after_rollback`` callbacks for all objects modified inside the +transaction. + +Example +~~~~~~~ + +This example uses the following models to represent documents that +describe books and films: + +.. literalinclude:: /includes/interact-data/transaction.rb + :start-after: start-example-models + :end-before: end-example-models + :language: ruby + :dedent: + +The following code demonstrates how to perform a transaction on +different objects to change data in multiple collections: + +.. literalinclude:: /includes/interact-data/transaction.rb + :start-after: start-txn-operations + :end-before: end-txn-operations + :language: ruby + :dedent: + +Client Limitations +~~~~~~~~~~~~~~~~~~ + +Only operations on the same client are in scope of a transaction, +because each transaction is attached to a specific client. Ensure +that you use objects from same client inside the transaction method +block. + +The following example defines model classes that use different clients +and demonstrates how operations are run based on the origin client: + +.. literalinclude:: /includes/interact-data/transaction.rb + :start-after: start-different-clients + :end-before: end-different-clients + :language: ruby + :dedent: + +.. note:: + + When you call the ``transaction()`` method on the ``{+odm+}`` module, + {+odm+} creates the transaction by using the ``:default`` client. + +Ending Transactions +~~~~~~~~~~~~~~~~~~~ + +Any exception raised inside the transaction method block ends the +transaction and rolls back changes. In most cases, {+odm+} displays the +exception, except for the ``Mongoid::Errors::Rollback`` exception. Implement +this exception in your application to explicitly end the transaction +without passing on an exception. + +Callbacks +~~~~~~~~~ + +This transaction API introduces the ``after_commit`` and +``after_rollback`` callbacks. + +{+odm+} triggers the ``after_commit`` callback for an object that was +created, saved, or destroyed in the following cases: + +- After the transaction is committed if the object was modified inside + the transaction. + +- After the object is persisted if the object was modified before + the transaction block. + +The ``after_commit`` callback is triggered only after all +other callbacks are executed successfully. Therefore, if an object is +modified without a transaction, it is possible that the object was +persisted, but the ``after_commit`` callback was not triggered, for +example, if {+odm+} raised an exception in the ``after_save`` callback. + +The ``after_rollback`` callback is triggered for an object that was +created, saved, or destroyed inside a transaction if the transaction was +ended. {+odm+} never triggers ``after_rollback`` outside of a transaction. + +.. _mongoid-txn-low-level: + +Lower Level API +--------------- + +When using the lower level API, you must create a session before +starting a transaction. You can create a session by calling the +``with_session()`` method on a model class or an instance of a model. + +Then, you can start a transaction by calling the ``start_transaction()`` +method on a session, as shown in the following code: + +.. literalinclude:: /includes/interact-data/transaction.rb + :start-after: start-lower-lvl-api + :end-before: end-lower-lvl-api + :language: ruby + :dedent: + +You can specify a read concern, write concern or read +preference when starting a transaction by passing options to the +``start_transaction()`` method: + +.. code-block:: ruby + + session.start_transaction( + read_concern: {level: :majority}, + write_concern: {w: 3}, + read: {mode: :primary} + ) + +When using this API, you must manually commit or end the transaction. +You can use the ``commit_transaction()`` and ``abort_transaction()`` +methods on the session instance to manage the transaction lifecycle: + +.. literalinclude:: /includes/interact-data/transaction.rb + :start-after: start-commit-abort + :end-before: end-commit-abort + :language: ruby + :dedent: + +.. note:: + + If a session ends and includes an open transaction, the transaction is + automatically ended. + +You can retry the transaction commit if it fails, +as shown in the following code: + +.. literalinclude:: /includes/interact-data/transaction.rb + :start-after: start-commit-retry + :end-before: end-commit-retry + :language: ruby + :dedent: + +Client Behavior +~~~~~~~~~~~~~~~ + +To perform operations within a transaction, operations must use the same +client that the session was initiated on. By default, all operations +are performed by using the default client. + +To explicitly use a different client, use the ``with()`` method: + +.. literalinclude:: /includes/interact-data/transaction.rb + :start-after: start-other-client + :end-before: end-other-client + :language: ruby + :dedent: + +.. _mongoid-txn-session: + +Perform Data Operations in a Session +------------------------------------ + +You can use sessions in {+odm+} in a similar way that you can +perform a transaction. You can call the ``with_session()`` method on a +model class or on an instance of a model and perform some operations in +a block. All operations in the block will be performed in the context of +single session. + +The following limitations apply when using sessions: + +- You cannot share a session across threads. Sessions are not thread-safe. + +- You cannot nest sessions. You cannot call the ``with_session()`` + method on a model class or a model instance within the block passed to + the ``with_session()`` method on another model class or model instance. + +- All model classes and instances used within the session block must use + the same driver client. For example, if you specify different + ``storage_options`` for another model used in the block than those of the + model or instance that you called ``with_session()`` on, {+odm+} returns + an error. + +Examples +~~~~~~~~ + +You can use the ``with_session()`` on a model class and pass it session +options to perform a block of operations in the context of a session. + +The following code enables the ``causal_consistency`` option when +creating a session, then performs data operations: + +.. literalinclude:: /includes/interact-data/transaction.rb + :start-after: start-model-session + :end-before: end-model-session + :language: ruby + :dedent: + +Alternatively, you can use the ``with_session()`` on an instance of a +model and pass it session options to perform a block of operations in +the context of a session. + +The following code enables the ``causal_consistency`` option when +creating a session, then performs data operations: + +.. literalinclude:: /includes/interact-data/transaction.rb + :start-after: start-instance-session + :end-before: end-instance-session + :language: ruby + :dedent: + +Additional Information +---------------------- + +To learn more about transactions, see :manual:`/core/transactions/` in +the {+server-manual+}. + +.. TODO To learn more about performing CRUD operations, see the :ref:`` guide. From 2d23fe4ed74ca88ec0389d0621268ceca0656140 Mon Sep 17 00:00:00 2001 From: rustagir Date: Tue, 12 Nov 2024 10:23:38 -0500 Subject: [PATCH 02/10] vale --- source/interact-data/transaction.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/interact-data/transaction.txt b/source/interact-data/transaction.txt index dca91cc3..c2f3004b 100644 --- a/source/interact-data/transaction.txt +++ b/source/interact-data/transaction.txt @@ -122,7 +122,7 @@ Ending Transactions ~~~~~~~~~~~~~~~~~~~ Any exception raised inside the transaction method block ends the -transaction and rolls back changes. In most cases, {+odm+} displays the +transaction and rolls back changes. Usually, {+odm+} displays the exception, except for the ``Mongoid::Errors::Rollback`` exception. Implement this exception in your application to explicitly end the transaction without passing on an exception. @@ -134,7 +134,7 @@ This transaction API introduces the ``after_commit`` and ``after_rollback`` callbacks. {+odm+} triggers the ``after_commit`` callback for an object that was -created, saved, or destroyed in the following cases: +created, saved, or deleted in the following cases: - After the transaction is committed if the object was modified inside the transaction. @@ -149,7 +149,7 @@ persisted, but the ``after_commit`` callback was not triggered, for example, if {+odm+} raised an exception in the ``after_save`` callback. The ``after_rollback`` callback is triggered for an object that was -created, saved, or destroyed inside a transaction if the transaction was +created, saved, or deleted inside a transaction if the transaction was ended. {+odm+} never triggers ``after_rollback`` outside of a transaction. .. _mongoid-txn-low-level: From b68d13e778a4395aa2f92254412fda721c8296e3 Mon Sep 17 00:00:00 2001 From: rustagir Date: Tue, 12 Nov 2024 10:24:03 -0500 Subject: [PATCH 03/10] link text --- source/interact-data/transaction.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/interact-data/transaction.txt b/source/interact-data/transaction.txt index c2f3004b..59b9038d 100644 --- a/source/interact-data/transaction.txt +++ b/source/interact-data/transaction.txt @@ -277,7 +277,7 @@ creating a session, then performs data operations: Additional Information ---------------------- -To learn more about transactions, see :manual:`/core/transactions/` in +To learn more about transactions, see :manual:`Transactions ` in the {+server-manual+}. .. TODO To learn more about performing CRUD operations, see the :ref:`` guide. From 6a11623e3ba9c62045723e39a51a12cac2ca6596 Mon Sep 17 00:00:00 2001 From: rustagir Date: Wed, 13 Nov 2024 12:28:08 -0500 Subject: [PATCH 04/10] MR PR fixes 1 --- snooty.toml | 1 + source/includes/interact-data/transaction.rb | 3 + source/interact-data/transaction.txt | 121 +++++++++++++------ 3 files changed, 85 insertions(+), 40 deletions(-) diff --git a/snooty.toml b/snooty.toml index 5b4584c2..c9983563 100644 --- a/snooty.toml +++ b/snooty.toml @@ -27,3 +27,4 @@ feedback-widget-title = "Feedback" server-manual = "Server manual" api-root = "https://www.mongodb.com/docs/mongoid/master/api/Mongoid" api = "https://www.mongodb.com/docs/mongoid/master/api" +ruby-api = "https://www.mongodb.com/docs/ruby-driver/current/api/Mongo" diff --git a/source/includes/interact-data/transaction.rb b/source/includes/interact-data/transaction.rb index 447bfc6e..fdfa3025 100644 --- a/source/includes/interact-data/transaction.rb +++ b/source/includes/interact-data/transaction.rb @@ -18,6 +18,7 @@ class Film # start-txn-operations # Starts a transaction from the model class Book.transaction do + # Saves new Book and Film instances to MongoDB Book.create(title: 'Covert Joy', author: 'Clarice Lispector') Film.create(title: 'Nostalgia', year: 1983) end @@ -25,12 +26,14 @@ class Film # Starts a transaction from an instance of Book book = Book.create(title: 'Sula', author: 'Toni Morrison') book.transaction do + # Saves a new field value to the Book instance book.length = 192 book.save! end # Starts a transaction from the Mongoid instance Mongoid.transaction do + # Deletes the Book instance in MongoDB book.destroy end # end-txn-operations diff --git a/source/interact-data/transaction.txt b/source/interact-data/transaction.txt index 59b9038d..b10c6058 100644 --- a/source/interact-data/transaction.txt +++ b/source/interact-data/transaction.txt @@ -25,32 +25,40 @@ In this guide, you can learn how to use {+odm+} to perform that change data only if the entire transaction is committed. If any operation in the transaction does not succeed, the driver stops the transaction and discards all data changes before they ever become -visible. This feature is called **atomicity**. +visible. This feature is called :wikipedia:`atomicity `. In MongoDB, transactions run within logical **sessions**. A session is a grouping of related read or write operations that you want to run sequentially. Sessions enable causal consistency for a group -of operations and allow you to run operations in an **ACID-compliant** +of operations, which means that all processes in your application agree on +the order of causally-related operations. + +Sessions allow you to run operations in an **ACID-compliant** transaction that meets an expectation of atomicity, consistency, isolation, and durability. MongoDB guarantees that the data involved in your transaction operations remains consistent, even if the operations encounter unexpected errors. -In {+odm+}, you can perform transactions by using the following APIs: +In {+odm+}, you can perform transactions by using either of the +following APIs: -- :ref:`mongoid-txn-high-level`: {+odm+} manages the life cycle of the +- :ref:`mongoid-txn-convenient`: {+odm+} manages the life cycle of the transaction. You can use this API in {+odm+} v9.0 and later. -- :ref:`mongoid-txn-low-level`: You must manage the life cycle of the +- :ref:`mongoid-txn-core`: You must manage the life cycle of the transaction. You can use this API in {+odm+} v6.4 and later. The :ref:`mongoid-txn-session` section describes how to make changes to your data from within a session without performing a transaction. -.. _mongoid-txn-high-level: +.. _mongoid-txn-convenient: + +Convenient Transaction API +-------------------------- -Higher Level API ----------------- +You can use the Convenient Transaction API to internally manage the +lifecycle of your transaction. This API either commits your transaction +or ends it and incorporates error handling logic. You can start a transaction by calling the ``transaction()`` method on an instance of a model, on the model class, or on a ``{+odm+}`` module. @@ -65,7 +73,7 @@ following tasks: #. Performs the specified data changes. #. Commits the transaction if no errors occur or ends the transaction if - there is an error. See the :ref:`` section to learn more an + there is an error. #. Closes the session. @@ -73,7 +81,8 @@ If your transaction is committed, {+odm+} calls any ``after_commit`` callbacks for all objects modified inside the transaction. If there is an error and the transaction is rolled back, {+odm+} calls any ``after_rollback`` callbacks for all objects modified inside the -transaction. +transaction. To learn more about this behavior, see the +:ref:`mongoid-txn-callbacks` section of this guide. Example ~~~~~~~ @@ -96,12 +105,12 @@ different objects to change data in multiple collections: :language: ruby :dedent: -Client Limitations -~~~~~~~~~~~~~~~~~~ +Client Behavior +~~~~~~~~~~~~~~~ -Only operations on the same client are in scope of a transaction, +Only operations on the same client are in the scope of a transaction, because each transaction is attached to a specific client. Ensure -that you use objects from same client inside the transaction method +that you use objects from the same client inside the transaction method block. The following example defines model classes that use different clients @@ -122,10 +131,14 @@ Ending Transactions ~~~~~~~~~~~~~~~~~~~ Any exception raised inside the transaction method block ends the -transaction and rolls back changes. Usually, {+odm+} displays the -exception, except for the ``Mongoid::Errors::Rollback`` exception. Implement -this exception in your application to explicitly end the transaction -without passing on an exception. +transaction and rolls back data changes. {+odm+} displays all +exceptions except for the ``Mongoid::Errors::Rollback`` exception. You +must raise this exception in your application to explicitly end the +transaction without returning the exception to you. You might implement +this transaction exception to end a transaction when a certain condition +is not met without raising an exception message. + +.. _mongoid-txn-callbacks: Callbacks ~~~~~~~~~ @@ -143,21 +156,26 @@ created, saved, or deleted in the following cases: the transaction block. The ``after_commit`` callback is triggered only after all -other callbacks are executed successfully. Therefore, if an object is -modified without a transaction, it is possible that the object was -persisted, but the ``after_commit`` callback was not triggered, for -example, if {+odm+} raised an exception in the ``after_save`` callback. +other callbacks are performed successfully. Therefore, if an object is +modified outside of a transaction, it is possible that the object is then +persisted, but the ``after_commit`` callback is not triggered. This +might occur, for example, if {+odm+} raised an exception in the +``after_save`` callback because this callback must complete successfully +to trigger ``after_commit``. The ``after_rollback`` callback is triggered for an object that was created, saved, or deleted inside a transaction if the transaction was -ended. {+odm+} never triggers ``after_rollback`` outside of a transaction. +ended. {+odm+} never triggers ``after_rollback`` outside of a +transaction. + +.. TODO link to callbacks guide. -.. _mongoid-txn-low-level: +.. _mongoid-txn-core: -Lower Level API ---------------- +Core Transaction API +-------------------- -When using the lower level API, you must create a session before +When using the Core API, you must create a session before starting a transaction. You can create a session by calling the ``with_session()`` method on a model class or an instance of a model. @@ -182,6 +200,11 @@ preference when starting a transaction by passing options to the read: {mode: :primary} ) +To learn more about the available transaction options, see +`start_transaction() +<{+ruby-api+}/Session.html#start_transaction-instance_method>`__ in the +{+ruby-driver+} API documentation. + When using this API, you must manually commit or end the transaction. You can use the ``commit_transaction()`` and ``abort_transaction()`` methods on the session instance to manage the transaction lifecycle: @@ -197,8 +220,9 @@ methods on the session instance to manage the transaction lifecycle: If a session ends and includes an open transaction, the transaction is automatically ended. -You can retry the transaction commit if it fails, -as shown in the following code: +You can retry the transaction commit if it fails initially. The +following example demonstrates how to retry the transaction when {+odm+} +raises the ``UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL`` exception: .. literalinclude:: /includes/interact-data/transaction.rb :start-after: start-commit-retry @@ -223,8 +247,8 @@ To explicitly use a different client, use the ``with()`` method: .. _mongoid-txn-session: -Perform Data Operations in a Session ------------------------------------- +Session API +----------- You can use sessions in {+odm+} in a similar way that you can perform a transaction. You can call the ``with_session()`` method on a @@ -236,24 +260,35 @@ The following limitations apply when using sessions: - You cannot share a session across threads. Sessions are not thread-safe. -- You cannot nest sessions. You cannot call the ``with_session()`` - method on a model class or a model instance within the block passed to - the ``with_session()`` method on another model class or model instance. +- You cannot nest sessions. For example, you cannot call the ``with_session()`` + method on a model class within the block passed to + the ``with_session()`` method on another model class. The following + code demonstrates a nested session that results in an error: + + .. code-block:: ruby + + Book.with_session(causal_consistency: true) do + # Nesting sessions results in errors + Film.with_session(causal_consistency: true) do + ... + end + end - All model classes and instances used within the session block must use the same driver client. For example, if you specify different - ``storage_options`` for another model used in the block than those of the + a different client for a model used in the block than those of the model or instance that you called ``with_session()`` on, {+odm+} returns an error. Examples ~~~~~~~~ -You can use the ``with_session()`` on a model class and pass it session +You can use the ``with_session()`` method on a model class and pass it session options to perform a block of operations in the context of a session. -The following code enables the ``causal_consistency`` option when -creating a session, then performs data operations: +The following code enables the ``causal_consistency`` option to +guarantee the order of operations when creating a session, then +performs data operations: .. literalinclude:: /includes/interact-data/transaction.rb :start-after: start-model-session @@ -261,12 +296,18 @@ creating a session, then performs data operations: :language: ruby :dedent: +To learn more about the available session options, see the +`Session class constructor details +<{+ruby-api+}/Session.html#initialize-instance_method>`__ in the +{+ruby-driver+} API documentation. + Alternatively, you can use the ``with_session()`` on an instance of a model and pass it session options to perform a block of operations in the context of a session. -The following code enables the ``causal_consistency`` option when -creating a session, then performs data operations: +The following code enables the ``causal_consistency`` option to +guarantee the order of operations when creating a session, then +performs data operations: .. literalinclude:: /includes/interact-data/transaction.rb :start-after: start-instance-session From c0eda4b6eed6788aed0810b9e8d7d0b8738fd397 Mon Sep 17 00:00:00 2001 From: rustagir Date: Thu, 14 Nov 2024 10:49:25 -0500 Subject: [PATCH 05/10] MR PR fixes 2 --- source/interact-data/transaction.txt | 32 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/source/interact-data/transaction.txt b/source/interact-data/transaction.txt index b10c6058..ed24faca 100644 --- a/source/interact-data/transaction.txt +++ b/source/interact-data/transaction.txt @@ -72,8 +72,8 @@ following tasks: #. Performs the specified data changes. -#. Commits the transaction if no errors occur or ends the transaction if - there is an error. +#. Commits the transaction to the database if no errors occur, or ends + the transaction if there is an error. #. Closes the session. @@ -81,8 +81,8 @@ If your transaction is committed, {+odm+} calls any ``after_commit`` callbacks for all objects modified inside the transaction. If there is an error and the transaction is rolled back, {+odm+} calls any ``after_rollback`` callbacks for all objects modified inside the -transaction. To learn more about this behavior, see the -:ref:`mongoid-txn-callbacks` section of this guide. +transaction. To learn more about these callbacks and their behavior, see +the :ref:`mongoid-txn-callbacks` section of this guide. Example ~~~~~~~ @@ -133,10 +133,10 @@ Ending Transactions Any exception raised inside the transaction method block ends the transaction and rolls back data changes. {+odm+} displays all exceptions except for the ``Mongoid::Errors::Rollback`` exception. You -must raise this exception in your application to explicitly end the -transaction without returning the exception to you. You might implement -this transaction exception to end a transaction when a certain condition -is not met without raising an exception message. +can raise this exception in your application to explicitly end the +transaction without returning the exception to you. For example, you +might implement this transaction exception to end a transaction when a +certain condition is not met, but without raising an exception message. .. _mongoid-txn-callbacks: @@ -164,9 +164,9 @@ might occur, for example, if {+odm+} raised an exception in the to trigger ``after_commit``. The ``after_rollback`` callback is triggered for an object that was -created, saved, or deleted inside a transaction if the transaction was -ended. {+odm+} never triggers ``after_rollback`` outside of a -transaction. +created, saved, or deleted inside a transaction, if the transaction was +unsuccessful and changes were rolled back. {+odm+} never triggers +``after_rollback`` outside of a transaction. .. TODO link to callbacks guide. @@ -287,8 +287,8 @@ You can use the ``with_session()`` method on a model class and pass it session options to perform a block of operations in the context of a session. The following code enables the ``causal_consistency`` option to -guarantee the order of operations when creating a session, then -performs data operations: +guarantee the order of operations when creating a session on the +``Book`` model, then performs data operations: .. literalinclude:: /includes/interact-data/transaction.rb :start-after: start-model-session @@ -301,13 +301,13 @@ To learn more about the available session options, see the <{+ruby-api+}/Session.html#initialize-instance_method>`__ in the {+ruby-driver+} API documentation. -Alternatively, you can use the ``with_session()`` on an instance of a +Alternatively, you can use the ``with_session()`` method on an instance of a model and pass it session options to perform a block of operations in the context of a session. The following code enables the ``causal_consistency`` option to -guarantee the order of operations when creating a session, then -performs data operations: +guarantee the order of operations when creating a session on an instance +of ``Book``, then performs data operations: .. literalinclude:: /includes/interact-data/transaction.rb :start-after: start-instance-session From d1e3bf3c6e155b5f8f7aec6113c4e409b073efbc Mon Sep 17 00:00:00 2001 From: rustagir Date: Thu, 14 Nov 2024 10:54:41 -0500 Subject: [PATCH 06/10] try using roles --- source/interact-data/transaction.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/interact-data/transaction.txt b/source/interact-data/transaction.txt index ed24faca..2c1b39c5 100644 --- a/source/interact-data/transaction.txt +++ b/source/interact-data/transaction.txt @@ -201,8 +201,8 @@ preference when starting a transaction by passing options to the ) To learn more about the available transaction options, see -`start_transaction() -<{+ruby-api+}/Session.html#start_transaction-instance_method>`__ in the +:ruby-api:`start_transaction() +` in the {+ruby-driver+} API documentation. When using this API, you must manually commit or end the transaction. @@ -297,8 +297,8 @@ guarantee the order of operations when creating a session on the :dedent: To learn more about the available session options, see the -`Session class constructor details -<{+ruby-api+}/Session.html#initialize-instance_method>`__ in the +:ruby-api:`Session class constructor details +` in the {+ruby-driver+} API documentation. Alternatively, you can use the ``with_session()`` method on an instance of a From d6eb2210685e35114ece90029d5a90b571eb1451 Mon Sep 17 00:00:00 2001 From: rustagir Date: Mon, 18 Nov 2024 16:45:20 -0500 Subject: [PATCH 07/10] DR tech review 1 --- source/includes/interact-data/transaction.rb | 23 +++---- source/interact-data/transaction.txt | 71 ++++++++++---------- 2 files changed, 46 insertions(+), 48 deletions(-) diff --git a/source/includes/interact-data/transaction.rb b/source/includes/interact-data/transaction.rb index fdfa3025..7848ffc7 100644 --- a/source/includes/interact-data/transaction.rb +++ b/source/includes/interact-data/transaction.rb @@ -63,28 +63,25 @@ class User # start-lower-lvl-api # Starts a session from the model class Book.with_session do |session| - # Starts the transaction in the session - session.start_transaction + session.start_transaction + # Creates a Book + Book.create(title: 'Siddhartha', author: 'Hermann Hesse') + + # Commits the transaction + session.commit_transaction +rescue StandardError + # Ends the transaction if there is an error + session.abort_transaction end book = Book.new -# Starts a session from an instance of Book +# Starts a session from an *instance* of Book book.with_session do |session| # Starts the transaction in the session session.start_transaction end # end-lower-lvl-api -# start-commit-abort -Book.with_session do |session| - session.commit_transaction -end - -Book.with_session do |session| - session.abort_transaction -end -# end-commit-abort - # start-commit-retry begin session.commit_transaction diff --git a/source/interact-data/transaction.txt b/source/interact-data/transaction.txt index 2c1b39c5..acde5fd4 100644 --- a/source/interact-data/transaction.txt +++ b/source/interact-data/transaction.txt @@ -42,21 +42,21 @@ encounter unexpected errors. In {+odm+}, you can perform transactions by using either of the following APIs: -- :ref:`mongoid-txn-convenient`: {+odm+} manages the life cycle of the +- :ref:`mongoid-txn-high-level`: {+odm+} manages the life cycle of the transaction. You can use this API in {+odm+} v9.0 and later. -- :ref:`mongoid-txn-core`: You must manage the life cycle of the +- :ref:`mongoid-txn-low-level`: You must manage the life cycle of the transaction. You can use this API in {+odm+} v6.4 and later. The :ref:`mongoid-txn-session` section describes how to make changes to your data from within a session without performing a transaction. -.. _mongoid-txn-convenient: +.. _mongoid-txn-high-level: -Convenient Transaction API +High-Level Transaction API -------------------------- -You can use the Convenient Transaction API to internally manage the +You can use the High-Level Transaction API to internally manage the lifecycle of your transaction. This API either commits your transaction or ends it and incorporates error handling logic. @@ -170,17 +170,28 @@ unsuccessful and changes were rolled back. {+odm+} never triggers .. TODO link to callbacks guide. -.. _mongoid-txn-core: +.. _mongoid-txn-low-level: -Core Transaction API --------------------- +Low-Level Transaction API +------------------------- -When using the Core API, you must create a session before +When using the low-level API, you must create a session before starting a transaction. You can create a session by calling the ``with_session()`` method on a model class or an instance of a model. Then, you can start a transaction by calling the ``start_transaction()`` -method on a session, as shown in the following code: +method on a session. When using this API, you must manually commit or +end the transaction. You can use the ``commit_transaction()`` and +``abort_transaction()`` methods on the session instance to manage the +transaction lifecycle. + +This example demonstrates how to use the low-level transaction API +to perform the following actions: + +- Create a session +- Start a transaction +- Perform data operations +- Commit the transaction, or end it if there are errors .. literalinclude:: /includes/interact-data/transaction.rb :start-after: start-lower-lvl-api @@ -188,6 +199,21 @@ method on a session, as shown in the following code: :language: ruby :dedent: +.. note:: + + If a session ends and includes an open transaction, the transaction is + automatically ended. + +You can retry the transaction commit if it fails initially. The +following example demonstrates how to retry the transaction when {+odm+} +raises the ``UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL`` exception: + +.. literalinclude:: /includes/interact-data/transaction.rb + :start-after: start-commit-retry + :end-before: end-commit-retry + :language: ruby + :dedent: + You can specify a read concern, write concern or read preference when starting a transaction by passing options to the ``start_transaction()`` method: @@ -205,31 +231,6 @@ To learn more about the available transaction options, see ` in the {+ruby-driver+} API documentation. -When using this API, you must manually commit or end the transaction. -You can use the ``commit_transaction()`` and ``abort_transaction()`` -methods on the session instance to manage the transaction lifecycle: - -.. literalinclude:: /includes/interact-data/transaction.rb - :start-after: start-commit-abort - :end-before: end-commit-abort - :language: ruby - :dedent: - -.. note:: - - If a session ends and includes an open transaction, the transaction is - automatically ended. - -You can retry the transaction commit if it fails initially. The -following example demonstrates how to retry the transaction when {+odm+} -raises the ``UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL`` exception: - -.. literalinclude:: /includes/interact-data/transaction.rb - :start-after: start-commit-retry - :end-before: end-commit-retry - :language: ruby - :dedent: - Client Behavior ~~~~~~~~~~~~~~~ From 24e68c4ff8f8d7efd7ef2fb1568c6d1eab00eebd Mon Sep 17 00:00:00 2001 From: rustagir Date: Mon, 18 Nov 2024 16:49:45 -0500 Subject: [PATCH 08/10] page fmt --- source/interact-data/transaction.txt | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/source/interact-data/transaction.txt b/source/interact-data/transaction.txt index acde5fd4..5ff81d7e 100644 --- a/source/interact-data/transaction.txt +++ b/source/interact-data/transaction.txt @@ -185,13 +185,16 @@ end the transaction. You can use the ``commit_transaction()`` and ``abort_transaction()`` methods on the session instance to manage the transaction lifecycle. -This example demonstrates how to use the low-level transaction API -to perform the following actions: +Example +~~~~~~~ + +This example uses the low-level transaction API to perform the following +actions: -- Create a session -- Start a transaction -- Perform data operations -- Commit the transaction, or end it if there are errors +1. Creates a session +#. Starts a transaction +#. Performs data operations +#. Commits the transaction, or ends it if there are errors .. literalinclude:: /includes/interact-data/transaction.rb :start-after: start-lower-lvl-api @@ -204,6 +207,9 @@ to perform the following actions: If a session ends and includes an open transaction, the transaction is automatically ended. +Transaction Retry +~~~~~~~~~~~~~~~~~ + You can retry the transaction commit if it fails initially. The following example demonstrates how to retry the transaction when {+odm+} raises the ``UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL`` exception: @@ -214,6 +220,9 @@ raises the ``UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL`` exception: :language: ruby :dedent: +Options +~~~~~~~ + You can specify a read concern, write concern or read preference when starting a transaction by passing options to the ``start_transaction()`` method: From d7478517b61373f109a8edaa06a130d0c06c5011 Mon Sep 17 00:00:00 2001 From: rustagir Date: Mon, 18 Nov 2024 16:51:47 -0500 Subject: [PATCH 09/10] page fmt --- source/includes/interact-data/transaction.rb | 7 ------- 1 file changed, 7 deletions(-) diff --git a/source/includes/interact-data/transaction.rb b/source/includes/interact-data/transaction.rb index 7848ffc7..ad8a74de 100644 --- a/source/includes/interact-data/transaction.rb +++ b/source/includes/interact-data/transaction.rb @@ -73,13 +73,6 @@ class User # Ends the transaction if there is an error session.abort_transaction end - -book = Book.new -# Starts a session from an *instance* of Book -book.with_session do |session| - # Starts the transaction in the session - session.start_transaction -end # end-lower-lvl-api # start-commit-retry From e0aae730bacc1dd55c2055d8d0a210477c63afd2 Mon Sep 17 00:00:00 2001 From: Rea Rustagi <85902999+rustagir@users.noreply.github.com> Date: Wed, 20 Nov 2024 15:42:49 -0500 Subject: [PATCH 10/10] DR small fix Co-authored-by: Dmitry Rybakov <160598371+comandeo-mongo@users.noreply.github.com> --- source/interact-data/transaction.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/interact-data/transaction.txt b/source/interact-data/transaction.txt index 5ff81d7e..04cef370 100644 --- a/source/interact-data/transaction.txt +++ b/source/interact-data/transaction.txt @@ -152,7 +152,7 @@ created, saved, or deleted in the following cases: - After the transaction is committed if the object was modified inside the transaction. -- After the object is persisted if the object was modified before +- After the object is persisted if the object was modified outside the transaction block. The ``after_commit`` callback is triggered only after all