diff --git a/app/models/alchemy/page/publisher.rb b/app/models/alchemy/page/publisher.rb index 07e9330997..62b76907f8 100644 --- a/app/models/alchemy/page/publisher.rb +++ b/app/models/alchemy/page/publisher.rb @@ -20,21 +20,23 @@ def initialize(page) # def publish!(public_on:) Page.transaction do - version = public_version(public_on) - DeleteElements.new(version.elements).call - - repository = page.draft_version.element_repository - ActiveRecord::Base.no_touching do - Element.acts_as_list_no_update do - repository.visible.not_nested.each.with_index(1) do |element, position| - Alchemy::DuplicateElement.new(element, repository: repository).call( - page_version_id: version.id, - position: position - ) + PageMutex.with_lock!(@page) do + version = public_version(public_on) + DeleteElements.new(version.elements).call + + repository = page.draft_version.element_repository + ActiveRecord::Base.no_touching do + Element.acts_as_list_no_update do + repository.visible.not_nested.each.with_index(1) do |element, position| + Alchemy::DuplicateElement.new(element, repository: repository).call( + page_version_id: version.id, + position: position + ) + end end end + page.update(published_at: public_on) end - page.update(published_at: public_on) end Alchemy.publish_targets.each { |p| p.perform_later(page) } diff --git a/spec/models/alchemy/page/publisher_spec.rb b/spec/models/alchemy/page/publisher_spec.rb index d43cb34d16..dc7962547d 100644 --- a/spec/models/alchemy/page/publisher_spec.rb +++ b/spec/models/alchemy/page/publisher_spec.rb @@ -95,5 +95,25 @@ publish end end + + context "in parallel" do + before do + # another publisher - instance created a mutex entry and locked the page + Alchemy::PageMutex.create(page: page, created_at: 5.seconds.ago) + end + + it "fails, if another process locked the page" do + expect { publish }.to raise_error Alchemy::PageMutex::LockFailed + end + + context "another page" do + let(:another_page) { create(:alchemy_page) } + let(:publisher) { described_class.new(another_page) } + + it "should allow the publishing of another page" do + expect { publish }.to change { another_page.versions.published.count }.by(1) + end + end + end end end