Rollbacks may not work as expected with multiple databases

When we have multiple write connections, the following code block will not work as expected:

ApplicationRecord.transaction do   # Or some other non Ci connection
  Ci::InstanceVariable.create!(key: 'somekey', value: 'abcd')

  raise ActiveRecord::Rollback     # Or any error
end

This issue is different from the cross-database modifications we have been exploring, this issue is more about the transaction you are expecting to rollback is on the wrong database.

  1. The list of ApplicationRecord.transaction:
ApplicationRecord.transaction list
$ gg ApplicationRecord.transaction
app/services/design_management/copy_design_collection/copy_service.rb:          ApplicationRecord.transaction do
app/services/feature_flags/create_service.rb:      ApplicationRecord.transaction do
app/services/feature_flags/destroy_service.rb:      ApplicationRecord.transaction do
app/services/feature_flags/update_service.rb:      ApplicationRecord.transaction do
app/services/issuable/clone/base_service.rb:        ApplicationRecord.transaction do
app/services/packages/create_dependency_service.rb:      ApplicationRecord.transaction do
app/services/packages/go/create_package_service.rb:        ApplicationRecord.transaction do
app/services/packages/npm/create_package_service.rb:        ApplicationRecord.transaction { create_npm_package! }
app/services/packages/terraform_module/create_package_service.rb:        ApplicationRecord.transaction { create_terraform_module_package! }
app/services/projects/cleanup_service.rb:      ApplicationRecord.transaction do
app/services/releases/update_service.rb:      ApplicationRecord.transaction do
doc/development/database/multiple_databases.md:ApplicationRecord.transaction do
doc/development/database/multiple_databases.md:  ApplicationRecord.transaction do
doc/development/database/transaction_guidelines.md:ApplicationRecord.transaction do
doc/development/database/transaction_guidelines.md:ApplicationRecord.transaction do
ee/app/services/analytics/devops_adoption/enabled_namespaces/bulk_delete_service.rb:          ApplicationRecord.transaction do
ee/app/services/app_sec/dast/profiles/create_service.rb:          ApplicationRecord.transaction do
ee/app/services/app_sec/dast/profiles/update_service.rb:          ApplicationRecord.transaction do
ee/app/services/app_sec/dast/site_profiles/create_service.rb:          ApplicationRecord.transaction do
ee/app/services/app_sec/dast/site_profiles/update_service.rb:          ApplicationRecord.transaction do
ee/app/services/approval_rules/finalize_service.rb:      ApplicationRecord.transaction do
ee/app/services/approval_rules/project_rule_destroy_service.rb:      ApplicationRecord.transaction do
ee/app/services/group_saml/group_managed_accounts/transfer_membership_service.rb:        ApplicationRecord.transaction do
ee/app/services/group_saml/sign_up_service.rb:      ApplicationRecord.transaction do
ee/app/services/iterations/cadences/destroy_service.rb:        ApplicationRecord.transaction do
ee/app/services/iterations/delete_service.rb:      ApplicationRecord.transaction do
ee/app/services/iterations/roll_over_issues_service.rb:        ApplicationRecord.transaction do
ee/app/services/security/ingestion/ingest_report_slice_service.rb:        ApplicationRecord.transaction do
ee/app/services/vulnerability_feedback/create_service.rb:      ApplicationRecord.transaction do
ee/app/services/vulnerability_feedback/create_service.rb:      ApplicationRecord.transaction do
ee/lib/ee/gitlab/background_migration/migrate_approver_to_approval_rules.rb:                ApplicationRecord.transaction do
lib/api/rubygem_packages.rb:            ApplicationRecord.transaction do
spec/initializers/forbid_sidekiq_in_transactions_spec.rb:  it 'forbids queue sidekiq worker in a Ci::ApplicationRecord transaction' do
spec/lib/gitlab/database/query_analyzers/prevent_cross_database_modification_spec.rb:            ApplicationRecord.transaction do
spec/rubocop/cop/performance/active_record_subtransactions_spec.rb:        ApplicationRecord.transaction(requires_new: true) do
spec/rubocop/cop/performance/active_record_subtransactions_spec.rb:        ApplicationRecord.transaction(isolation: :read_committed, requires_new: true) do
spec/rubocop/cop/performance/active_record_subtransactions_spec.rb:        ApplicationRecord.transaction(requires_new: false) do
spec/rubocop/cop/performance/active_record_subtransactions_spec.rb:        ApplicationRecord.transaction(isolation: :read_committed) do
spec/rubocop/cop/performance/active_record_subtransactions_spec.rb:        ApplicationRecord.transaction do
  1. This applies to instances where we use other classes like Project.transaction

  2. Similar issue with ActiveRecord::Base.transaction

Edited Dec 08, 2021 by Thong Kuah
Assignee Loading
Time tracking Loading