Skip to content

Commit

Permalink
Added prorate for ip limit rate.
Browse files Browse the repository at this point in the history
Signed-off-by: EdmondFrank <[email protected]>
  • Loading branch information
EdmondFrank committed Feb 6, 2024
1 parent 8da89d1 commit bf36f58
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 1 deletion.
3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ gem 'redis'

gem 'redis-rails'

# Provides a low-level time-based throttle.
gem 'prorate'

# Use RabbitMQ
gem 'bunny'
gem 'sneakers'
Expand Down
5 changes: 4 additions & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,8 @@ GEM
parser (3.1.2.0)
ast (~> 2.4.1)
promise.rb (0.7.4)
prorate (0.7.3)
redis (>= 2)
pry (0.14.1)
coderay (~> 1.1)
method_source (~> 1.0)
Expand Down Expand Up @@ -685,7 +687,7 @@ GEM
activesupport (>= 6.1.5)
i18n
rbtree (0.4.5)
redis (4.6.0)
redis (4.8.1)
redis-actionpack (5.3.0)
actionpack (>= 5, < 8)
redis-rack (>= 2.1.0, < 3)
Expand Down Expand Up @@ -937,6 +939,7 @@ DEPENDENCIES
opentelemetry-sdk
overcommit
pagy
prorate
pry
puma
pundit (~> 2.3)
Expand Down
31 changes: 31 additions & 0 deletions app/controllers/graphql_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,51 @@ def execute
variables = prepare_variables(params[:variables])
query = params[:query]
operation_name = params[:operationName]

context = {
current_user: current_user,
sign_out: method(:sign_out),
cookies: cookies
}

t = Prorate::Throttle.new(
name: "global-api-limit",
limit: 1000,
period: 1.hour,
block_for: 1.hour,
redis: throttle_redis,
logger: Rails.logger
)

real_ip =
case request.host
when 'compass.gitee.com'
request.env['HTTP_X_FORWARDED_FOR']&.split(',')&.first
else
request.remote_ip
end

t << real_ip

t.throttle! if !current_user || real_ip

result = CompassWebServiceSchema.execute(query, variables: variables, context: context, operation_name: operation_name)
render json: result
rescue Prorate::Throttled => e
logger.warn("blocking #{request.remote_ip} Retry-After #{e.retry_in_seconds}")
response.set_header('Retry-After', e.retry_in_seconds.to_s)
render json: { errors: [{ message: e.message, retry_fater: e.retry_in_seconds }], data: {} }, status: 429
rescue StandardError => e
raise e unless Rails.env.development?
handle_error_in_development(e)
end

private

def throttle_redis
@throttle_redis ||= Redis.new(url: ENV.fetch('REDIS_URL') { 'redis://redis:6379/1' })
end

# Handle variables in form data, JSON body, or a blank value
def prepare_variables(variables_param)
case variables_param
Expand Down

0 comments on commit bf36f58

Please sign in to comment.