Commit b05fb24b authored by Douwe Maan's avatar Douwe Maan

Merge branch '5049-fix-transaction-raised-error-in-mirroring' into 'master'

Resolve "`RepositoryRemoveRemoteWorker.perform_async` being called from transaction"

Closes #5049

See merge request gitlab-org/gitlab-ee!4747
parents b505a110 130e060e
...@@ -18,13 +18,26 @@ module Sidekiq ...@@ -18,13 +18,26 @@ module Sidekiq
%i(perform_async perform_at perform_in).each do |name| %i(perform_async perform_at perform_in).each do |name|
define_method(name) do |*args| define_method(name) do |*args|
if !Sidekiq::Worker.skip_transaction_check && AfterCommitQueue.inside_transaction? if !Sidekiq::Worker.skip_transaction_check && AfterCommitQueue.inside_transaction?
raise Sidekiq::Worker::EnqueueFromTransactionError, <<~MSG begin
raise Sidekiq::Worker::EnqueueFromTransactionError, <<~MSG
`#{self}.#{name}` cannot be called inside a transaction as this can lead to `#{self}.#{name}` cannot be called inside a transaction as this can lead to
race conditions when the worker runs before the transaction is committed and race conditions when the worker runs before the transaction is committed and
tries to access a model that has not been saved yet. tries to access a model that has not been saved yet.
Use an `after_commit` hook, or include `AfterCommitQueue` and use a `run_after_commit` block instead. Use an `after_commit` hook, or include `AfterCommitQueue` and use a `run_after_commit` block instead.
MSG MSG
rescue Sidekiq::Worker::EnqueueFromTransactionError => e
if Rails.env.production?
Rails.logger.error(e.message)
if Gitlab::Sentry.enabled?
Gitlab::Sentry.context
Raven.capture_exception(e)
end
else
raise
end
end
end end
super(*args) super(*args)
......
...@@ -337,7 +337,9 @@ module EE ...@@ -337,7 +337,9 @@ module EE
end end
def remove_mirror_repository_reference def remove_mirror_repository_reference
repository.async_remove_remote(::Repository::MIRROR_REMOTE) run_after_commit do
repository.async_remove_remote(::Repository::MIRROR_REMOTE)
end
end end
def username_only_import_url def username_only_import_url
......
...@@ -24,7 +24,8 @@ class RemoteMirror < ActiveRecord::Base ...@@ -24,7 +24,8 @@ class RemoteMirror < ActiveRecord::Base
after_save :set_override_remote_mirror_available, unless: -> { Gitlab::CurrentSettings.current_application_settings.mirror_available } after_save :set_override_remote_mirror_available, unless: -> { Gitlab::CurrentSettings.current_application_settings.mirror_available }
after_save :refresh_remote, if: :mirror_url_changed? after_save :refresh_remote, if: :mirror_url_changed?
after_update :reset_fields, if: :mirror_url_changed? after_update :reset_fields, if: :mirror_url_changed?
after_destroy :remove_remote
after_commit :remove_remote, on: :destroy
scope :enabled, -> { where(enabled: true) } scope :enabled, -> { where(enabled: true) }
scope :started, -> { with_update_status(:started) } scope :started, -> { with_update_status(:started) }
......
---
title: Supresses error being raised due to async remote removal being run outside
a transaction
merge_request: 4747
author:
type: fixed
...@@ -328,6 +328,16 @@ describe Project do ...@@ -328,6 +328,16 @@ describe Project do
end end
end end
describe 'updating import_url' do
it 'removes previous remote' do
project = create(:project, :repository, :mirror)
expect(RepositoryRemoveRemoteWorker).to receive(:perform_async).with(project.id, ::Repository::MIRROR_REMOTE).and_call_original
project.update_attributes(import_url: "http://test.com")
end
end
describe '#mirror_waiting_duration' do describe '#mirror_waiting_duration' do
it 'returns in seconds the time spent in the queue' do it 'returns in seconds the time spent in the queue' do
project = create(:project, :mirror, :import_scheduled) project = create(:project, :mirror, :import_scheduled)
......
...@@ -70,6 +70,14 @@ describe RemoteMirror do ...@@ -70,6 +70,14 @@ describe RemoteMirror do
config = repo.raw_repository.rugged.config config = repo.raw_repository.rugged.config
expect(config["remote.#{mirror.remote_name}.url"]).to eq('http://foo:baz@test.com') expect(config["remote.#{mirror.remote_name}.url"]).to eq('http://foo:baz@test.com')
end end
it 'removes previous remote' do
mirror = create_mirror(url: 'http://foo:bar@test.com')
expect(RepositoryRemoveRemoteWorker).to receive(:perform_async).with(mirror.project.id, mirror.remote_name).and_call_original
mirror.update_attributes(url: 'http://test.com')
end
end end
end end
...@@ -120,6 +128,16 @@ describe RemoteMirror do ...@@ -120,6 +128,16 @@ describe RemoteMirror do
end end
end end
context 'when remote mirror gets destroyed' do
it 'removes remote' do
mirror = create_mirror(url: 'http://foo:bar@test.com')
expect(RepositoryRemoveRemoteWorker).to receive(:perform_async).with(mirror.project.id, mirror.remote_name).and_call_original
mirror.destroy!
end
end
context 'stuck mirrors' do context 'stuck mirrors' do
it 'includes mirrors stuck in started with no last_update_at set' do it 'includes mirrors stuck in started with no last_update_at set' do
mirror = create_mirror(url: 'http://cantbeblank', mirror = create_mirror(url: 'http://cantbeblank',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment