Skip to content

Commit

Permalink
tmp: reproduce bug from #258
Browse files Browse the repository at this point in the history
  • Loading branch information
BuonOmo committed Jan 31, 2025
1 parent 56a37d8 commit 7cacf6c
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 1 deletion.
5 changes: 4 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,7 @@ jobs:
done
cat ${{ github.workspace }}/setup.sql | cockroach sql --insecure
- name: Test
run: bundle exec rake test TESTOPTS='--profile=5'
run: bundle exec rake test
env:
AR_LOG: "stdout"
TESTOPTS: "--name=test_concurrent_insert_with_processes"
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,27 @@ def within_new_transaction(isolation: nil, joinable: true, attempts: 0)
within_new_transaction(isolation: isolation, joinable: joinable, attempts: attempts + 1) { yield }
end

# OVERRIDE: the `rescue ActiveRecord::StatementInvalid` block is new, see comment.
def rollback_transaction(transaction = nil)
@connection.lock.synchronize do
transaction ||= @stack.last
begin
transaction.rollback
rescue ActiveRecord::StatementInvalid => err
# This is important to make Active Record aware the record was not inserted/saved
# Otherwise Active Record will assume save was successful and it doesn't retry the transaction
# See this thread for more details:
# https://github.com/cockroachdb/activerecord-cockroachdb-adapter/issues/258#issuecomment-2256633329
transaction.rollback_records if err.cause.is_a?(PG::NoActiveSqlTransaction)

raise
ensure
@stack.pop if @stack.last == transaction
end
transaction.rollback_records
end
end

def retryable?(error)
return true if serialization_error?(error)
return true if error.is_a? ActiveRecord::SerializationFailure
Expand Down
52 changes: 52 additions & 0 deletions test/cases/transactions_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# frozen_string_literal: true

require "cases/helper_cockroachdb"

module CockroachDB
class TransactionsTest < ActiveRecord::TestCase
self.use_transactional_tests = false

class Avenger < ActiveRecord::Base
validate :validate_unique_username

def validate_unique_username
duplicate = Avenger.where(name: name).any?
errors.add("Duplicate username!") if duplicate
end
end

def setup
conn = ActiveRecord::Base.lease_connection
conn.create_table :avengers, force: true do |t|
t.string :name
end
Avenger.reset_column_information
end

def teardown
conn = ActiveRecord::Base.lease_connection
conn.drop_table :avengers, if_exists: true
end

def test_concurrent_insert_with_processes
avengers = %w(Hulk Thor IronMan)
before_barrier = Concurrent::CyclicBarrier.new(avengers.size)
after_barrier = Concurrent::CyclicBarrier.new(avengers.size)
pids = []
Thread.current[:name] = "Main"

avengers.map do |name|
Thread.fork do
Thread.current[:name] = name
before_barrier.wait
Avenger.create!(name: name)
after_barrier.wait
end
end.each(&:join)

assert_equal avengers.size, Avenger.count
ensure
Thread.current[:name] = nil
end
end
end

0 comments on commit 7cacf6c

Please sign in to comment.