Commit 354207d1 authored by Alper Akgun's avatar Alper Akgun

Merge branch 'catch-timeout-update-max-seats-worker' into 'master'

Catch Timeouts in UpdateMaxSeatsUsedForGitlabComSubscriptionsWorker

See merge request gitlab-org/gitlab!61741
parents e3be5309 94ff9719
...@@ -21,6 +21,8 @@ class UpdateMaxSeatsUsedForGitlabComSubscriptionsWorker # rubocop:disable Scalab ...@@ -21,6 +21,8 @@ class UpdateMaxSeatsUsedForGitlabComSubscriptionsWorker # rubocop:disable Scalab
subscription.refresh_seat_attributes! subscription.refresh_seat_attributes!
tuples << [subscription.id, subscription.max_seats_used, subscription.seats_in_use, subscription.seats_owed] tuples << [subscription.id, subscription.max_seats_used, subscription.seats_in_use, subscription.seats_owed]
rescue ActiveRecord::QueryCanceled => e
track_error(e, subscription)
end end
if tuples.present? if tuples.present?
...@@ -42,9 +44,9 @@ class UpdateMaxSeatsUsedForGitlabComSubscriptionsWorker # rubocop:disable Scalab ...@@ -42,9 +44,9 @@ class UpdateMaxSeatsUsedForGitlabComSubscriptionsWorker # rubocop:disable Scalab
private private
def track_error(subscription) def track_error(error, subscription)
Gitlab::ErrorTracking.track_exception( Gitlab::ErrorTracking.track_exception(
StandardError.new('Namespace absent'), error,
gitlab_subscription_id: subscription.id, gitlab_subscription_id: subscription.id,
namespace_id: subscription.namespace_id namespace_id: subscription.namespace_id
) )
......
...@@ -3,95 +3,133 @@ ...@@ -3,95 +3,133 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe UpdateMaxSeatsUsedForGitlabComSubscriptionsWorker do RSpec.describe UpdateMaxSeatsUsedForGitlabComSubscriptionsWorker do
subject { described_class.new } describe '#perform' do
subject { described_class.new }
let_it_be(:bronze_plan) { create(:bronze_plan) } let_it_be(:bronze_plan) { create(:bronze_plan) }
let_it_be(:gitlab_subscription, refind: true) { create(:gitlab_subscription, seats: 1) } let_it_be(:gitlab_subscription, refind: true) { create(:gitlab_subscription, seats: 1) }
let_it_be(:gitlab_subscription_2, refind: true) { create(:gitlab_subscription, seats: 11) } let_it_be(:gitlab_subscription_2, refind: true) { create(:gitlab_subscription, seats: 11) }
let(:db_is_read_only) { false } let(:db_is_read_only) { false }
let(:subscription_attrs) { nil } let(:subscription_attrs) { nil }
before do before do
allow(Gitlab::Database).to receive(:read_only?) { db_is_read_only } allow(Gitlab::Database).to receive(:read_only?) { db_is_read_only }
allow(Gitlab::CurrentSettings).to receive(:should_check_namespace_plan?) { true } allow(Gitlab::CurrentSettings).to receive(:should_check_namespace_plan?) { true }
allow_next_found_instance_of(GitlabSubscription) do |subscription|
allow(subscription).to receive(:refresh_seat_attributes!) do
subscription.max_seats_used = subscription.seats + 3
subscription.seats_in_use = subscription.seats + 2
subscription.seats_owed = subscription.seats + 1
end
end end
end
def perform_and_reload def perform_and_reload
subject.perform subject.perform
gitlab_subscription.reload gitlab_subscription.reload
gitlab_subscription_2.reload gitlab_subscription_2.reload
end
shared_examples 'updates nothing' do
it 'does not update seat columns' do
expect do
perform_and_reload
end.to not_change(gitlab_subscription, :max_seats_used)
.and not_change(gitlab_subscription, :seats_in_use)
.and not_change(gitlab_subscription, :seats_owed)
.and not_change(gitlab_subscription_2, :max_seats_used)
.and not_change(gitlab_subscription_2, :seats_in_use)
.and not_change(gitlab_subscription_2, :seats_owed)
end end
end
shared_examples 'updates only paid plans' do shared_examples 'updates nothing' do
it "persists seat attributes after refresh_seat_attributes! for only paid plans" do it 'does not update seat columns' do
expect do expect do
perform_and_reload perform_and_reload
end.to not_change(gitlab_subscription, :max_seats_used) end.to not_change(gitlab_subscription, :max_seats_used)
.and not_change(gitlab_subscription, :seats_in_use) .and not_change(gitlab_subscription, :seats_in_use)
.and not_change(gitlab_subscription, :seats_owed) .and not_change(gitlab_subscription, :seats_owed)
.and change(gitlab_subscription_2, :max_seats_used).from(0).to(14) .and not_change(gitlab_subscription_2, :max_seats_used)
.and change(gitlab_subscription_2, :seats_in_use).from(0).to(13) .and not_change(gitlab_subscription_2, :seats_in_use)
.and change(gitlab_subscription_2, :seats_owed).from(0).to(12) .and not_change(gitlab_subscription_2, :seats_owed)
end
end end
end
context 'where the DB is read-only' do shared_examples 'updates only paid plans' do
let(:db_is_read_only) { true } it "persists seat attributes after refresh_seat_attributes! for only paid plans" do
expect do
perform_and_reload
end.to not_change(gitlab_subscription, :max_seats_used)
.and not_change(gitlab_subscription, :seats_in_use)
.and not_change(gitlab_subscription, :seats_owed)
.and change(gitlab_subscription_2, :max_seats_used).from(0).to(14)
.and change(gitlab_subscription_2, :seats_in_use).from(0).to(13)
.and change(gitlab_subscription_2, :seats_owed).from(0).to(12)
end
end
include_examples 'updates nothing' context 'where the DB is read-only' do
end let(:db_is_read_only) { true }
context 'when the DB is not read-only' do include_examples 'updates nothing'
before do
gitlab_subscription.update!(subscription_attrs) if subscription_attrs
end end
context 'with a free plan' do context 'when the DB is not read-only' do
let(:subscription_attrs) { { hosted_plan: nil } } before do
gitlab_subscription.update!(subscription_attrs) if subscription_attrs
allow_next_found_instance_of(GitlabSubscription) do |subscription|
allow(subscription).to receive(:refresh_seat_attributes!) do
subscription.max_seats_used = subscription.seats + 3
subscription.seats_in_use = subscription.seats + 2
subscription.seats_owed = subscription.seats + 1
end
end
end
include_examples 'updates only paid plans' context 'with a free plan' do
end let(:subscription_attrs) { { hosted_plan: nil } }
context 'with a trial plan' do include_examples 'updates only paid plans'
let(:subscription_attrs) { { hosted_plan: bronze_plan, trial: true } } end
include_examples 'updates only paid plans' context 'with a trial plan' do
let(:subscription_attrs) { { hosted_plan: bronze_plan, trial: true } }
include_examples 'updates only paid plans'
end
context 'with a paid plan', :aggregate_failures do
before do
gitlab_subscription.update!(hosted_plan: bronze_plan)
gitlab_subscription_2.update!(hosted_plan: bronze_plan)
end
it 'persists seat attributes after refresh_seat_attributes' do
expect do
perform_and_reload
end.to change(gitlab_subscription, :max_seats_used).from(0).to(4)
.and change(gitlab_subscription, :seats_in_use).from(0).to(3)
.and change(gitlab_subscription, :seats_owed).from(0).to(2)
.and change(gitlab_subscription_2, :max_seats_used).from(0).to(14)
.and change(gitlab_subscription_2, :seats_in_use).from(0).to(13)
.and change(gitlab_subscription_2, :seats_owed).from(0).to(12)
end
end
end end
context 'with a paid plan', :aggregate_failures do context 'when a statement timeout exception is thrown for a subscription' do
before do before do
gitlab_subscription.update!(hosted_plan: bronze_plan) allow_next_found_instance_of(GitlabSubscription) do |subscription|
gitlab_subscription_2.update!(hosted_plan: bronze_plan) allow(subscription).to receive(:refresh_seat_attributes!) do
if subscription.id == gitlab_subscription.id
raise ActiveRecord::QueryCanceled, 'statement timeout'
else
subscription.max_seats_used = subscription.seats + 3
subscription.seats_in_use = subscription.seats + 2
subscription.seats_owed = subscription.seats + 1
end
end
end
end
it 'catches and logs the exception' do
expect(Gitlab::ErrorTracking).to receive(:track_exception).with(
an_instance_of(ActiveRecord::QueryCanceled),
{ gitlab_subscription_id: gitlab_subscription.id,
namespace_id: gitlab_subscription.namespace_id })
perform_and_reload
end end
it 'persists seat attributes after refresh_seat_attributes' do it 'successfully updates remaining subscriptions' do
expect do expect do
perform_and_reload perform_and_reload
end.to change(gitlab_subscription, :max_seats_used).from(0).to(4) end.to not_change(gitlab_subscription, :max_seats_used).from(0)
.and change(gitlab_subscription, :seats_in_use).from(0).to(3) .and not_change(gitlab_subscription, :seats_in_use).from(0)
.and change(gitlab_subscription, :seats_owed).from(0).to(2) .and not_change(gitlab_subscription, :seats_owed).from(0)
.and change(gitlab_subscription_2, :max_seats_used).from(0).to(14) .and change(gitlab_subscription_2, :max_seats_used).from(0).to(14)
.and change(gitlab_subscription_2, :seats_in_use).from(0).to(13) .and change(gitlab_subscription_2, :seats_in_use).from(0).to(13)
.and change(gitlab_subscription_2, :seats_owed).from(0).to(12) .and change(gitlab_subscription_2, :seats_owed).from(0).to(12)
......
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