Skip to content

Commit

Permalink
Put binding and job creation in one transaction
Browse files Browse the repository at this point in the history
Similar as in #3567, now for service key binding and service instance
creation to be consistent with #3567.
  • Loading branch information
kathap committed Jan 29, 2024
1 parent 2ac31c2 commit eb89740
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 13 deletions.
9 changes: 5 additions & 4 deletions app/controllers/v3/service_credential_bindings_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ def create
when 'key'
unauthorized! unless can_write_to_active_space?(service_instance.space)
suspended! unless is_space_active?(service_instance.space)

create_key_binding(message, service_instance)
end
rescue V3::ServiceCredentialBindingAppCreate::UnprocessableCreate,
Expand Down Expand Up @@ -182,10 +181,12 @@ def override_default_order_by(message)

def create_key_binding(message, service_instance)
action = V3::ServiceCredentialBindingKeyCreate.new(user_audit_info, message.audit_hash)
binding = action.precursor(service_instance, message:)
VCAP::CloudController::ServiceBinding.db.transaction do
binding = action.precursor(service_instance, message:)

pollable_job_guid = enqueue_bind_job(:key, binding.guid, message)
head :accepted, 'Location' => url_builder.build_url(path: "/v3/jobs/#{pollable_job_guid}")
pollable_job_guid = enqueue_bind_job(:key, binding.guid, message)
head :accepted, 'Location' => url_builder.build_url(path: "/v3/jobs/#{pollable_job_guid}")
end
end

def build_create_message(params)
Expand Down
21 changes: 12 additions & 9 deletions app/controllers/v3/service_instances_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -257,17 +257,20 @@ def create_managed(message, space:)
unprocessable_service_plan! unless service_plan_valid?(service_plan, space)

action = V3::ServiceInstanceCreateManaged.new(user_audit_info, message.audit_hash)
instance = action.precursor(message:, service_plan:)
VCAP::CloudController::ServiceInstance.db.transaction do
instance = action.precursor(message:, service_plan:)

provision_job = VCAP::CloudController::V3::CreateServiceInstanceJob.new(
instance.guid,
arbitrary_parameters: message.parameters,
user_audit_info: user_audit_info,
audit_hash: message.audit_hash
)
pollable_job = Jobs::Enqueuer.new(provision_job, queue: Jobs::Queues.generic).enqueue_pollable
provision_job = VCAP::CloudController::V3::CreateServiceInstanceJob.new(
instance.guid,
arbitrary_parameters: message.parameters,
user_audit_info: user_audit_info,
audit_hash: message.audit_hash
)

pollable_job = Jobs::Enqueuer.new(provision_job, queue: Jobs::Queues.generic).enqueue_pollable

head :accepted, 'Location' => url_builder.build_url(path: "/v3/jobs/#{pollable_job.guid}")
head :accepted, 'Location' => url_builder.build_url(path: "/v3/jobs/#{pollable_job.guid}")
end
rescue VCAP::CloudController::ServiceInstanceCreateMixin::UnprocessableOperation,
V3::ServiceInstanceCreateManaged::InvalidManagedServiceInstance => e
unprocessable!(e.message)
Expand Down
17 changes: 17 additions & 0 deletions spec/request/service_instances_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1174,6 +1174,23 @@ def check_filtered_instances(*instances)
end
end

describe 'when db is unavailable' do
before do
allow_any_instance_of(VCAP::CloudController::Jobs::Enqueuer).to receive(:enqueue_pollable).and_raise(Sequel::DatabaseDisconnectError)
end

it 'rolls back the transaction' do
api_call.call(admin_headers)

expect(last_response).to have_status_code(503)
expect(parsed_response['errors']).to include(include({
'detail' => include('Database connection failure'),
'title' => 'CF-ServiceUnavailable',
'code' => 10_015
}))
end
end

describe 'service plan checks' do
context 'does not exist' do
let(:service_plan_guid) { 'does-not-exist' }
Expand Down

0 comments on commit eb89740

Please sign in to comment.