Skip to content

Commit c954428

Browse files
committed
Adjust rate limits for service-related endpoints.
Most if not all service broker operations for the CF API v3 have been moved into background jobs and are asynchronous operations. This means that the service broker operation can't block anymore the CF API v3 requests (which returns a 202 and a link to the polling job). After reviewing /v3/service related endpoints, we adapted the rate limiting: - v3 service related endpoints that never interact with SBs synchronously are removed from rate limiting (POST, PATCH, DELETE /v3/[service_instances|service_credential_bindings|service_route_bindings]) - v3 GET methods that interact with SBs synchronously are added to rate limiting (/v3/(service_instances|service_credential_bindings|service_route_bindings)/.+/parameters)
1 parent 76b958e commit c954428

File tree

2 files changed

+30
-14
lines changed

2 files changed

+30
-14
lines changed

middleware/service_broker_rate_limiter.rb

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@
33

44
module CloudFoundry
55
module Middleware
6+
RateLimitEndpoint = Struct.new(:endpoint_pattern, :methods)
7+
8+
RATE_LIMITED_ENDPOINTS = [
9+
RateLimitEndpoint.new(%r{\A/v2/(service_instances|service_credential_bindings|service_route_bindings)}, %w[PUT POST DELETE PATCH]),
10+
RateLimitEndpoint.new(%r{\A/v3/(service_instances|service_credential_bindings|service_route_bindings)/.+/parameters\z}, %w[GET]),
11+
RateLimitEndpoint.new(%r{\A/v3/(service_instances|service_credential_bindings|service_route_bindings)}, %w[PUT])
12+
].freeze
13+
614
class ConcurrentRequestCounter
715
def initialize(key_prefix, redis_connection_pool_size: nil)
816
@key_prefix = key_prefix
@@ -106,26 +114,17 @@ def call(env)
106114

107115
def apply_rate_limiting?(env)
108116
request = ActionDispatch::Request.new(env)
109-
!admin? && is_service_request?(request) && rate_limit_method?(request)
117+
!admin? && rate_limit_method?(request)
110118
end
111119

112120
def admin?
113121
VCAP::CloudController::SecurityContext.admin? || VCAP::CloudController::SecurityContext.admin_read_only?
114122
end
115123

116-
def is_service_request?(request)
117-
[
118-
%r{\A/v2/service_instances},
119-
%r{\A/v2/service_bindings},
120-
%r{\A/v2/service_keys},
121-
%r{\A/v3/service_instances},
122-
%r{\A/v3/service_credential_bindings},
123-
%r{\A/v3/service_route_bindings}
124-
].any? { |re| request.fullpath.match(re) }
125-
end
126-
127124
def rate_limit_method?(request)
128-
%w[PATCH PUT POST DELETE].include?(request.method)
125+
RATE_LIMITED_ENDPOINTS.any? do |endpoint|
126+
endpoint.endpoint_pattern.match?(request.fullpath) && endpoint.methods.include?(request.method)
127+
end
129128
end
130129

131130
def suggested_retry_after

spec/unit/middleware/service_broker_rate_limiter_spec.rb

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ module Middleware
88
let(:path_info) { '/v3/service_instances' }
99
let(:user_guid) { SecureRandom.uuid }
1010
let(:user_env) { { 'cf.user_guid' => user_guid, 'PATH_INFO' => path_info } }
11-
let(:fake_request) { instance_double(ActionDispatch::Request, fullpath: '/v3/service_instances', method: 'POST') }
11+
let(:fake_request) { instance_double(ActionDispatch::Request, fullpath: '/v3/service_instances', method: 'PUT') }
1212
let(:max_concurrent_requests) { 1 }
1313
let(:broker_timeout) { 60 }
1414
let(:middleware) do
@@ -25,6 +25,8 @@ module Middleware
2525
end
2626

2727
describe 'included requests' do
28+
let(:request_method) { 'PUT' } # Adjust as needed to test different HTTP methods
29+
2830
it 'allows a service broker request within the limit' do
2931
status, = middleware.call(user_env)
3032
expect(status).to eq(200)
@@ -117,6 +119,21 @@ module Middleware
117119
end
118120
end
119121

122+
describe 'excluded requests' do
123+
let(:request_method) { 'POST' }
124+
125+
it 'allows requests that are no longer rate limited' do
126+
status, = middleware.call(user_env)
127+
expect(status).to eq(200)
128+
129+
status, = middleware.call(user_env)
130+
expect(status).to eq(200)
131+
132+
statuses = 2.times.map { middleware.call(user_env).first }
133+
expect(statuses).to match_array([200, 200])
134+
end
135+
end
136+
120137
describe 'skipped requests' do
121138
let(:concurrent_request_counter) { double }
122139

0 commit comments

Comments
 (0)