diff options
| -rw-r--r-- | app/models/referential.rb | 2 | ||||
| -rw-r--r-- | spec/models/referential/referential_lock_during_creation_spec.rb | 51 | 
2 files changed, 52 insertions, 1 deletions
| diff --git a/app/models/referential.rb b/app/models/referential.rb index b44bb15c6..6cdab8fb7 100644 --- a/app/models/referential.rb +++ b/app/models/referential.rb @@ -210,7 +210,7 @@ class Referential < ActiveRecord::Base    # Lock the `referentials` table to prevent duplicate referentials from being    # created simultaneously in separate transactions. This must be the last hook    # to minimise the duration of the lock. -  before_validation :lock_table, on: :create +  before_save :lock_table, on: [:create, :update]    before_create :create_schema    after_create :clone_schema, if: :created_from diff --git a/spec/models/referential/referential_lock_during_creation_spec.rb b/spec/models/referential/referential_lock_during_creation_spec.rb index d17327d39..169162af9 100644 --- a/spec/models/referential/referential_lock_during_creation_spec.rb +++ b/spec/models/referential/referential_lock_during_creation_spec.rb @@ -76,6 +76,57 @@ RSpec.describe Referential, type: :model do        end      end +    it "works asynchronously when one is updated", truncation: true do +      begin +        referential_1 = nil +        referential_2 = nil + +        ActiveRecord::Base.transaction do +          referential_1 = create( +            :referential, +            workbench: workbench, +            organisation: workbench.organisation +          ) +          referential_2 = referential_1.dup +          referential_2.name = 'Another' +          referential_2.slug = "#{referential_1.slug}_different" +          referential_2.save! +        end + +        metadata_2 = build(:referential_metadata, referential: nil) +        metadata_1 = metadata_2.dup + +        thread_1 = Thread.new do +          ActiveRecord::Base.transaction do +            # seize LOCK +            referential_1.metadatas_attributes = [metadata_1.attributes] +            puts referential_1.save +            sleep 10 +            # release LOCK +          end +        end + +        thread_2 = Thread.new do +          sleep 5 +          ActiveRecord::Base.transaction do +            # waits for LOCK, (because of sleep 5) +            referential_2.metadatas_attributes = [metadata_2.attributes] +            puts referential_2.save +          end +        end + +        thread_1.join +        thread_2.join + +        expect(referential_1).to be_valid +        expect(referential_2).not_to be_valid +      ensure +        Apartment::Tenant.drop(referential_1.slug) if referential_1.persisted? +        Apartment::Tenant.drop(referential_2.slug) if referential_2.persisted? +      end +    end +  end +    context "when two Referentials are created at the same time" do      it "raises an error when the DB lock timeout is reached", truncation: true do        begin | 
