Rails: Handling actions that need to happen after all transactions

Posted . Visible to the public. Repeats.

In Rails 7.2. the feature ActiveRecord.after_all_transactions_commit was added, for code that may run either inside or outside a transaction (we have a special card for nested transactions in general) and needs to perform work after the state changes have been properly persisted. e.g. sending an email.

Example

def publish_article(article)
  article.update(published: true)

  ActiveRecord.after_all_transactions_commit do
    PublishNotificationMailer.with(article: article).deliver_later
  end
end

For most use cases there is no action needed at all, since common job interfaces enqueue their jobs after all transactions commit by default e.g. sidekiq Show archive.org snapshot . In the past we used the gem after_transaction_commit Show archive.org snapshot for custom handling, which now can be replaced by the build-in functionality of Rails.

Note: This doesn't solve issues, where you want to have a specific order of after_commit actions.

Documented behavior

Taken from the API documentation Show archive.org snapshot

  • Registers a block to be called after all the current transactions have been committed.
  • If there is no currently open transaction, the block is called immediately.
  • If there are multiple nested transactions, the block is called after the outermost one has been committed,
  • If any of the currently open transactions is rolled back, the block is never called.
  • If multiple transactions are open across multiple databases, the block will be invoked if and once all of them have been committed. But note that nesting transactions across two distinct databases is a sharding anti-pattern that comes with a world of hurts.
Last edit
Michael Leimstädtner
License
Source code in this card is licensed under the MIT License.
Posted by Emanuel to makandra dev (2025-08-04 10:53)