Skip to content

Commit

Permalink
Add PageMutex to Publisher
Browse files Browse the repository at this point in the history
Prevent publishing the same page at the same time. The PageMutex is locking the page for the time it takes until the page is published. After that the lock is released and it can publish again.
  • Loading branch information
sascha-karnatz committed Nov 14, 2023
1 parent e3291d8 commit 48edabe
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 12 deletions.
26 changes: 14 additions & 12 deletions app/models/alchemy/page/publisher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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) }
Expand Down
20 changes: 20 additions & 0 deletions spec/models/alchemy/page/publisher_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 48edabe

Please sign in to comment.