diff options
Diffstat (limited to 'app')
-rw-r--r-- | app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue | 8 | ||||
-rw-r--r-- | app/controllers/projects/merge_requests_controller.rb | 2 | ||||
-rw-r--r-- | app/helpers/environments_helper.rb | 1 | ||||
-rw-r--r-- | app/models/environment.rb | 4 | ||||
-rw-r--r-- | app/models/merge_request.rb | 32 |
5 files changed, 42 insertions, 5 deletions
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue index 339e154affc..57be97855e3 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue @@ -65,9 +65,13 @@ export default { simplePoll(this.checkRebaseStatus); }) .catch(error => { - this.rebasingError = error.merge_error; this.isMakingRequest = false; - Flash(__('Something went wrong. Please try again.')); + + if (error.response && error.response.data && error.response.data.merge_error) { + this.rebasingError = error.response.data.merge_error; + } else { + Flash(__('Something went wrong. Please try again.')); + } }); }, checkRebaseStatus(continuePolling, stopPolling) { diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index e6032323c13..8d388151dbc 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -226,6 +226,8 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo @merge_request.rebase_async(current_user.id) head :ok + rescue MergeRequest::RebaseLockTimeout => e + render json: { merge_error: e.message }, status: :conflict end def discussions diff --git a/app/helpers/environments_helper.rb b/app/helpers/environments_helper.rb index c642a64ad61..f57d0fa19d4 100644 --- a/app/helpers/environments_helper.rb +++ b/app/helpers/environments_helper.rb @@ -34,6 +34,7 @@ module EnvironmentsHelper "project-path" => project_path(project), "tags-path" => project_tags_path(project), "has-metrics" => "#{environment.has_metrics?}", + "prometheus-status" => "#{environment.prometheus_status}", "external-dashboard-url" => project.metrics_setting_external_dashboard_url } end diff --git a/app/models/environment.rb b/app/models/environment.rb index af0c219d9a0..b426941d8af 100644 --- a/app/models/environment.rb +++ b/app/models/environment.rb @@ -188,6 +188,10 @@ class Environment < ApplicationRecord prometheus_adapter.query(:environment, self) if has_metrics? end + def prometheus_status + deployment_platform&.cluster&.application_prometheus&.status_name + end + def additional_metrics(*args) return unless has_metrics? diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 6ef84c5f59b..b1c7e778743 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -220,6 +220,10 @@ class MergeRequest < ApplicationRecord alias_attribute :auto_merge_enabled, :merge_when_pipeline_succeeds alias_method :issuing_parent, :target_project + RebaseLockTimeout = Class.new(StandardError) + + REBASE_LOCK_MESSAGE = _("Failed to enqueue the rebase operation, possibly due to a long-lived transaction. Try again later.") + def self.reference_prefix '!' end @@ -409,9 +413,7 @@ class MergeRequest < ApplicationRecord # Set off a rebase asynchronously, atomically updating the `rebase_jid` of # the MR so that the status of the operation can be tracked. def rebase_async(user_id) - transaction do - lock! - + with_rebase_lock do raise ActiveRecord::StaleObjectError if !open? || rebase_in_progress? # Although there is a race between setting rebase_jid here and clearing it @@ -1468,6 +1470,30 @@ class MergeRequest < ApplicationRecord private + def with_rebase_lock + if Feature.enabled?(:merge_request_rebase_nowait_lock, default_enabled: true) + with_retried_nowait_lock { yield } + else + with_lock(true) { yield } + end + end + + # If the merge request is idle in transaction or has a SELECT FOR + # UPDATE, we don't want to block indefinitely or this could cause a + # queue of SELECT FOR UPDATE calls. Instead, try to get the lock for + # 5 s before raising an error to the user. + def with_retried_nowait_lock + # Try at most 0.25 + (1.5 * .25) + (1.5^2 * .25) ... (1.5^5 * .25) = 5.2 s to get the lock + Retriable.retriable(on: ActiveRecord::LockWaitTimeout, tries: 6, base_interval: 0.25) do + with_lock('FOR UPDATE NOWAIT') do + yield + end + end + rescue ActiveRecord::LockWaitTimeout => e + Gitlab::Sentry.track_acceptable_exception(e) + raise RebaseLockTimeout, REBASE_LOCK_MESSAGE + end + def source_project_variables Gitlab::Ci::Variables::Collection.new.tap do |variables| break variables unless source_project |