From c858936af02359096c93938058b84b37d2d868c7 Mon Sep 17 00:00:00 2001 From: Katharina Przybill <30441792+kathap@users.noreply.github.com> Date: Thu, 8 Aug 2024 15:23:51 +0200 Subject: [PATCH] Prevent 500 on parallel org quota creation To apply this change the migration from https://github.com/cloudfoundry/cloud_controller_ng/pull/3923 needs to be in first. Tha-s why we ceeated the adoption to prevetn 500 on concurrent requests for organization_quota_create separately. The reason is the same as in #3899 and #3918. --- app/models/runtime/quota_definition.rb | 9 +++++++++ .../organization_quotas_create_spec.rb | 20 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/app/models/runtime/quota_definition.rb b/app/models/runtime/quota_definition.rb index 09a216b282e..738570d1bc3 100644 --- a/app/models/runtime/quota_definition.rb +++ b/app/models/runtime/quota_definition.rb @@ -19,6 +19,15 @@ class QuotaDefinition < Sequel::Model :app_instance_limit, :app_task_limit, :total_service_keys, :total_reserved_route_ports, :log_rate_limit + def around_save + yield + rescue Sequel::UniqueConstraintViolation => e + raise e unless e.message.include?('qd_name_index') + + errors.add(:name, :unique) + raise validation_failed_error + end + def validate validates_presence :name validates_unique :name diff --git a/spec/unit/actions/organization_quotas_create_spec.rb b/spec/unit/actions/organization_quotas_create_spec.rb index c95052f871a..c6817e57c2b 100644 --- a/spec/unit/actions/organization_quotas_create_spec.rb +++ b/spec/unit/actions/organization_quotas_create_spec.rb @@ -132,6 +132,26 @@ module VCAP::CloudController end end + context 'when creating organization quotas concurrently' do + let(:name) { 'awesome' } + let(:message) { VCAP::CloudController::OrganizationQuotasCreateMessage.new(name:) } + + it 'ensures one creation is successful and the other fails due to name conflict' do + # First request, should succeed + expect do + org_quotas_create.create(message) + end.not_to raise_error + + # Mock the validation for the second request to simulate the race condition and trigger a unique constraint violation + allow_any_instance_of(QuotaDefinition).to receive(:validate).and_return(true) + + # Second request, should fail with correct error + expect do + org_quotas_create.create(message) + end.to raise_error(OrganizationQuotasCreate::Error, "Organization Quota 'awesome' already exists.") + end + end + context 'when the org guid is invalid' do let(:invalid_org_guid) { 'invalid_org_guid' } let(:message_with_invalid_org_guid) do