Uploaded image for project: 'Mongoid'
  1. Mongoid
  2. MONGOID-5531

Add after_commit and after_rollback callbacks

    • Type: Icon: New Feature New Feature
    • Resolution: Fixed
    • Priority: Icon: Unknown Unknown
    • 9.0.0
    • Affects Version/s: None
    • Component/s: None
    • Labels:
      None

      after_commit is triggered on every document saved or destroyed:

      • if there is a transaction, the callback is triggered immediately after the transaction is committed. This naturally happens after all other callbacks completed successfully.
      • if there is no transaction, the callback is triggered after the corresponding persistence operation completed and all other callbacks completed successfully.

      after_rollback is triggered on every document saved or destroyed:

      • if there is a transaction, the callback triggered immediately after the transaction is rolled back.
      • this callback is not triggered if there is no transaction.

      *We will consider introducing an optional implicit transactions in Mongoid.

      Rationale

      In ActiveRecord save and destroy operations are automatically wrapped in a transaction. Therefore, transactional callbacks are always triggered, even if a used did not open a transaction explicitly. This is a desired and expected behavior.

      In contrast, Mongoid does not wrap operations in transactions. Therefore, if we want to achieve the same behavior as Rails, we have to trigger the callbacks without a transaction. However, there are still gotchas that do not allow us to exactly copy AR.

      It would be semantically correct to trigger this callback if and only if the persistence operation was completed successfully. However, this is different from the AR behavior. In AR, if there is an exception raised in after_save callback, the implicit transaction will be rolled back, and after_rollback will be triggered instead. And what is maybe even more important - the persistence operation will be reverted.

      We cannot do the same in Mongoid without a transaction. If the persistence operation completed, there is no way to revert it, even if an exception in raised in after_save. Since a fully AR-compatible behavior is not achievable, we can only decide what we can sacrifice.

      after_commit

      We believe that if there is no transaction, the after_commit callback should be triggered the latest, only if all other callbacks completed successfully. This is semantically close to what AR does. The tradeoff here is it is possible that a document was persisted, but its after_commit wasn't called. But this can happen if there was an exception raised in an after_* callback. So, a user has a chance to handle this situation.

      after_rollback

      As to after_rollback, we believe that this callback should not be triggered at all if there is no transaction. In case of after_commit happy path without a transaction we can end up in a situation that is equivalent to the one in AR; for after_rollback this is not going to happen.
       
       Add :on option to after_commit and after_rollback callbacks (https://jira.mongodb.org/browse/MONGOID-5058)

            Assignee:
            dmitry.rybakov@mongodb.com Dmitry Rybakov
            Reporter:
            dmitry.rybakov@mongodb.com Dmitry Rybakov
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved: