diff --git a/Changelog.md b/Changelog.md index 5787dc9ca64a7f6fe7ab8fc5aea0b99e77bb7d6a..b6ce3f0666c3ee91b4cf15ab72db1c1207b392ff 100644 --- a/Changelog.md +++ b/Changelog.md @@ -38,6 +38,7 @@ after you've upgraded. * Cleanup relayables where the signature is missing [#7637](https://github.com/diaspora/diaspora/pull/7637) * Avoid page to jump to top after a post deletion [#7638](https://github.com/diaspora/diaspora/pull/7638) * Handle duplicate account deletions [#7639](https://github.com/diaspora/diaspora/pull/7639) +* Handle duplicate account migrations [#7641](https://github.com/diaspora/diaspora/pull/7641) ## Features * Ask for confirmation when leaving a submittable comment field [#7530](https://github.com/diaspora/diaspora/pull/7530) diff --git a/lib/diaspora/federation/receive.rb b/lib/diaspora/federation/receive.rb index 13e235de11a7ec0d9eb8bfcb36e58e5fbf2ea2ea..d4dcea34ddc344fcfacf4c1e10e81b1db4a1a13b 100644 --- a/lib/diaspora/federation/receive.rb +++ b/lib/diaspora/federation/receive.rb @@ -18,11 +18,14 @@ module Diaspora end def self.account_migration(entity) + old_person = author_of(entity) profile = profile(entity.profile) - AccountMigration.create!( - old_person: Person.by_account_identifier(entity.author), - new_person: profile.person - ) + return if AccountMigration.where(old_person: old_person, new_person: profile.person).exists? + AccountMigration.create!(old_person: old_person, new_person: profile.person) + rescue => e # rubocop:disable Lint/RescueWithoutErrorClass + raise e unless AccountMigration.where(old_person: old_person, new_person: profile.person).exists? + logger.warn "ignoring error on receive #{entity}: #{e.class}: #{e.message}" + nil end def self.comment(entity) diff --git a/spec/integration/federation/receive_federation_messages_spec.rb b/spec/integration/federation/receive_federation_messages_spec.rb index 5ab47dbcc2a816f00bedfdcde792d24b5b292678..c9a67aeb4972ff37433cbd194c16b8b9b599f05b 100644 --- a/spec/integration/federation/receive_federation_messages_spec.rb +++ b/spec/integration/federation/receive_federation_messages_spec.rb @@ -58,11 +58,12 @@ describe "Receive federation messages feature" do expect(AccountMigration.find_by(old_person: sender.person, new_person: new_user.person)).to be_performed end - it "doesn't accept the same migration for the second time" do + it "doesn't run the same migration for the second time" do run_migration - expect { - run_migration - }.to raise_error(ActiveRecord::RecordInvalid) + expect_any_instance_of(AccountMigration).not_to receive(:perform!) + run_migration + expect(AccountMigration.where(old_person: sender.person, new_person: new_user.person).count).to eq(1) + expect(AccountMigration.find_by(old_person: sender.person, new_person: new_user.person)).to be_performed end it "doesn't accept second migration for the same sender" do diff --git a/spec/lib/diaspora/federation/receive_spec.rb b/spec/lib/diaspora/federation/receive_spec.rb index 1fd76b08d1b47a90751b32284d06d705aab9c57c..2c2e7e1106135eed12fe83d83bd7feebfc13a508 100644 --- a/spec/lib/diaspora/federation/receive_spec.rb +++ b/spec/lib/diaspora/federation/receive_spec.rb @@ -47,6 +47,27 @@ describe Diaspora::Federation::Receive do expect(AccountMigration.exists?(old_person: sender, new_person: new_person)).to be_truthy end + + it "ignores duplicate the account migrations" do + AccountMigration.create(old_person: sender, new_person: new_person) + + expect(AccountMigration).not_to receive(:create!) + + expect(Diaspora::Federation::Receive.account_migration(account_migration_entity)).to be_nil + + expect(AccountMigration.exists?(old_person: sender, new_person: new_person)).to be_truthy + end + + it "handles race conditions on parallel receive" do + expect(AccountMigration).to receive(:create!) do + AccountMigration.create(old_person: sender, new_person: new_person) + raise "Some database error" + end + + expect(Diaspora::Federation::Receive.account_migration(account_migration_entity)).to be_nil + + expect(AccountMigration.exists?(old_person: sender, new_person: new_person)).to be_truthy + end end describe ".comment" do