From f688c284709b9f49a87df378ff3130d03c414e8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Serdar=20=C3=96zer?= Date: Thu, 13 Aug 2026 14:44:47 +0200 Subject: [PATCH] feat: concurrency ratelimiter specs are added --- jobs/cloud_controller_ng/spec | 16 ++++++++ .../templates/cloud_controller_ng.yml.erb | 7 ++++ .../cloud_controller_ng_spec.rb | 37 +++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/jobs/cloud_controller_ng/spec b/jobs/cloud_controller_ng/spec index 1c7c2a1981..b3aea3a8bf 100644 --- a/jobs/cloud_controller_ng/spec +++ b/jobs/cloud_controller_ng/spec @@ -1114,6 +1114,22 @@ properties: description: "The interval in minutes after which a user's available API requests will be reset" default: 60 + cc.concurrency_rate_limiter.enabled: + description: "Enable concurrency rate limiting for UAA-authenticated endpoints per user or client" + default: false + cc.concurrency_rate_limiter.blocking_limit: + description: "Maximum number of concurrent requests per user before blocking. Use -1 to disable" + default: 10 + cc.concurrency_rate_limiter.logging_limit: + description: "Number of concurrent requests per user at which to start logging warnings. Use -1 to disable." + default: 5 + cc.concurrency_rate_limiter.redis_connection_pool_size: + description: "Redis connection pool size for the concurrency rate limiter, should match total puma threads" + default: 40 + cc.concurrency_rate_limiter.redis_counter_ttl_seconds: + description: "TTL in seconds for concurrency counter keys in Redis. Should be aligned with the request timeout to ensure counters expire if a request never completes." + default: 901 + cc.max_concurrent_service_broker_requests: description: "Maximum number of concurrent requests to service brokers per user. Set to 0 to not limit concurrent requests" default: 0 diff --git a/jobs/cloud_controller_ng/templates/cloud_controller_ng.yml.erb b/jobs/cloud_controller_ng/templates/cloud_controller_ng.yml.erb index c7f69f1ca7..fafe487c9d 100644 --- a/jobs/cloud_controller_ng/templates/cloud_controller_ng.yml.erb +++ b/jobs/cloud_controller_ng/templates/cloud_controller_ng.yml.erb @@ -498,6 +498,13 @@ rate_limiter: per_process_admin_limit: <%= p("cc.rate_limiter.admin_limit") == -1 ? -1 : (p("cc.rate_limiter.admin_limit").to_f/instances).ceil %> reset_interval_in_minutes: <%= p("cc.rate_limiter.reset_interval_in_minutes") %> +concurrency_rate_limiter: + enabled: <%= p("cc.concurrency_rate_limiter.enabled") %> + blocking_limit: <%= p("cc.concurrency_rate_limiter.blocking_limit") %> + logging_limit: <%= p("cc.concurrency_rate_limiter.logging_limit") %> + redis_connection_pool_size: <%= p("cc.concurrency_rate_limiter.redis_connection_pool_size") %> + redis_counter_ttl_seconds: <%= p("cc.concurrency_rate_limiter.redis_counter_ttl_seconds") %> + max_concurrent_service_broker_requests: <%= p("cc.max_concurrent_service_broker_requests") %> <% instances = p("cc.rate_limiter_v2_api.enabled") ? link("cloud_controller").instances.length : 1 %> diff --git a/spec/cloud_controller_ng/cloud_controller_ng_spec.rb b/spec/cloud_controller_ng/cloud_controller_ng_spec.rb index b1d749ef75..f62d09d10b 100644 --- a/spec/cloud_controller_ng/cloud_controller_ng_spec.rb +++ b/spec/cloud_controller_ng/cloud_controller_ng_spec.rb @@ -473,6 +473,43 @@ module Test end end + context 'when concurrency rate limiting is configured' do + before do + merged_manifest_properties['cc']['concurrency_rate_limiter'] = { + 'enabled' => true, + 'blocking_limit' => 20, + 'logging_limit' => 10, + 'redis_connection_pool_size' => 40, + 'redis_counter_ttl_seconds' => 901 + } + end + + it 'enables concurrency rate limiting' do + template_hash = YAML.safe_load(template.render(merged_manifest_properties, consumes: links)) + expect(template_hash['concurrency_rate_limiter']['enabled']).to be(true) + end + + it 'sets blocking_limit' do + template_hash = YAML.safe_load(template.render(merged_manifest_properties, consumes: links)) + expect(template_hash['concurrency_rate_limiter']['blocking_limit']).to eq(20) + end + + it 'sets logging_limit' do + template_hash = YAML.safe_load(template.render(merged_manifest_properties, consumes: links)) + expect(template_hash['concurrency_rate_limiter']['logging_limit']).to eq(10) + end + + it 'sets redis_connection_pool_size' do + template_hash = YAML.safe_load(template.render(merged_manifest_properties, consumes: links)) + expect(template_hash['concurrency_rate_limiter']['redis_connection_pool_size']).to eq(40) + end + + it 'sets redis_counter_ttl_seconds' do + template_hash = YAML.safe_load(template.render(merged_manifest_properties, consumes: links)) + expect(template_hash['concurrency_rate_limiter']['redis_counter_ttl_seconds']).to eq(901) + end + end + describe 'enable v2 API' do it 'is by default false' do template_hash = YAML.safe_load(template.render(merged_manifest_properties, consumes: links))