Skip to content

Commit

Permalink
encode timestamp to the redis key
Browse files Browse the repository at this point in the history
  • Loading branch information
y-tabata committed Jun 12, 2018
1 parent 19f37eb commit 396f259
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 21 deletions.
14 changes: 8 additions & 6 deletions gateway/src/apicast/policy/rate_limit/rate_limit.lua
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,13 @@ local function init_error_settings(limits_exceeded_error, configuration_error)
return error_settings
end

local function build_limiters_and_keys(type, limiters, redis, error_settings, context)
local function build_limiters_and_keys(type, limiters, redis, error_settings, context, timestamp)
local res_limiters = {}
local res_keys = {}

for _, limiter in ipairs(limiters) do
local lim, initerr = traffic_limiters[type](limiter)
local window = limiter.window or 0
if not lim then
ngx.log(ngx.ERR, "unknown limiter: ", type, ", err: ", initerr)
error(error_settings, "configuration_issue")
Expand All @@ -133,9 +134,9 @@ local function build_limiters_and_keys(type, limiters, redis, error_settings, co
local key = limiter.template_string:render(
ngx_variable.available_context(context))
if limiter.key.scope == "global" then
key = format("%s_%s", type, key)
key = format("%d_%s_%s", timestamp + window, type, key)
else
key = format("%s_%s_%s", context.service.id, type, key)
key = format("%d_%s_%s_%s", timestamp + window, context.service.id, type, key)
end

insert(res_keys, key)
Expand All @@ -160,6 +161,7 @@ function _M.new(config)
self.redis_url = config.redis_url
self.error_settings = init_error_settings(
config.limits_exceeded_error, config.configuration_error)
self.timestamp = ngx.time()

for _, limiters in ipairs({ self.connection_limiters, self.leaky_bucket_limiters, self.fixed_window_limiters }) do
build_templates(limiters)
Expand All @@ -181,13 +183,13 @@ function _M:access(context)
end

local conn_limiters, conn_keys = build_limiters_and_keys(
'connections', self.connection_limiters, red, self.error_settings, context)
'connections', self.connection_limiters, red, self.error_settings, context, self.timestamp)

local leaky_bucket_limiters, leaky_bucket_keys = build_limiters_and_keys(
'leaky_bucket', self.leaky_bucket_limiters, red, self.error_settings, context)
'leaky_bucket', self.leaky_bucket_limiters, red, self.error_settings, context, self.timestamp)

local fixed_window_limiters, fixed_window_keys = build_limiters_and_keys(
'fixed_window', self.fixed_window_limiters, red, self.error_settings, context)
'fixed_window', self.fixed_window_limiters, red, self.error_settings, context, self.timestamp)

local limiters = {}
local limiter_groups = { conn_limiters, leaky_bucket_limiters, fixed_window_limiters }
Expand Down
26 changes: 22 additions & 4 deletions spec/policy/rate_limit/rate_limit_spec.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
local RateLimitPolicy = require('apicast.policy.rate_limit')
local match = require('luassert.match')
local env = require('resty.env')
local ipairs = ipairs
local insert = table.insert
local function init_val()
ngx.var = {}
ngx.var.request_time = '0.060'
Expand Down Expand Up @@ -38,6 +40,12 @@ assert:register("matcher", "gt", is_gt)
local redis_host = env.get('TEST_NGINX_REDIS_HOST') or 'localhost'
local redis_port = env.get('TEST_NGINX_REDIS_PORT') or 6379

local function convert(table_a, table_b)
for _, v in ipairs(table_b) do
insert(table_a, v)
end
end

describe('Rate limit policy', function()
local ngx_exit_spy
local ngx_sleep_spy
Expand All @@ -52,7 +60,14 @@ describe('Rate limit policy', function()
local redis = require('resty.redis'):new()
redis:connect(redis_host, redis_port)
redis:select(1)
redis:del('connections_test1', 'leaky_bucket_test2', 'fixed_window_test3', '5_leaky_bucket_test4')
local keys = {}
convert(keys, redis:keys('*_connections_test1'))
convert(keys, redis:keys('*_leaky_bucket_test2'))
convert(keys, redis:keys('*_fixed_window_test3'))
convert(keys, redis:keys('*_5_leaky_bucket_test4'))
for _, key in ipairs(keys) do
redis:del(key)
end
init_val()
context = {
service = {
Expand Down Expand Up @@ -148,7 +163,8 @@ describe('Rate limit policy', function()
local redis = require('resty.redis'):new()
redis:connect(redis_host, redis_port)
redis:select(1)
local fixed_window = redis:get('fixed_window_test3')
local redis_key = redis:keys('*_fixed_window_test3')[1]
local fixed_window = redis:get(redis_key)
assert.equal('2', fixed_window)
end)

Expand All @@ -168,7 +184,8 @@ describe('Rate limit policy', function()
local redis = require('resty.redis'):new()
redis:connect(redis_host, redis_port)
redis:select(1)
local fixed_window = redis:get('fixed_window_test3')
local redis_key = redis:keys('*_fixed_window_test3')[1]
local fixed_window = redis:get(redis_key)
assert.equal('2', fixed_window)
end)

Expand All @@ -187,7 +204,8 @@ describe('Rate limit policy', function()
local redis = require('resty.redis'):new()
redis:connect(redis_host, redis_port)
redis:select(1)
local fixed_window = redis:get('fixed_window_test3')
local redis_key = redis:keys('*_fixed_window_test3')[1]
local fixed_window = redis:get(redis_key)
assert.equal('2', fixed_window)
end)

Expand Down
37 changes: 26 additions & 11 deletions t/apicast-policy-rate-limit.t
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ Return 200 code.
local redis = require('resty.redis'):new()
redis:connect(redis_host, redis_port)
redis:select(1)
redis:del("42_connections_test1")
local redis_key = redis:keys('*_42_connections_test1')[1]
redis:del(redis_key)
}
}
Expand Down Expand Up @@ -159,7 +160,8 @@ Return 200 code.
local redis = require('resty.redis'):new()
redis:connect(redis_host, redis_port)
redis:select(1)
redis:del("42_connections_test2")
local redis_key = redis:keys('*_42_connections_test2')[1]
redis:del(redis_key)
}
}
Expand Down Expand Up @@ -277,7 +279,8 @@ Return 200 code.
local redis = require('resty.redis'):new()
redis:connect(redis_host, redis_port)
redis:select(1)
redis:del("connections_test4")
local redis_key = redis:keys('*_connections_test4')[1]
redis:del(redis_key)
}
}
Expand Down Expand Up @@ -394,7 +397,10 @@ Return 200 code.
local redis = require('resty.redis'):new()
redis:connect(redis_host, redis_port)
redis:select(1)
redis:del("leaky_bucket_test6_1", "connections_test6_2", "fixed_window_test6_3")
local redis_key1 = redis:keys('*_leaky_bucket_test6_1')[1]
local redis_key2 = redis:keys('*_connections_test6_2')[1]
local redis_key3 = redis:keys('*_fixed_window_test6_3')[1]
redis:del(redis_key1, redis_key2, redis_key3)
}
}
Expand Down Expand Up @@ -469,7 +475,8 @@ Return 429 code.
local redis = require('resty.redis'):new()
redis:connect(redis_host, redis_port)
redis:select(1)
redis:del("connections_test7")
local redis_key = redis:keys('*_connections_test7')[1]
redis:del(redis_key)
}
}
Expand Down Expand Up @@ -529,7 +536,8 @@ Return 503 code.
local redis = require('resty.redis'):new()
redis:connect(redis_host, redis_port)
redis:select(1)
redis:del("leaky_bucket_test8")
local redis_key = redis:keys('*_leaky_bucket_test8')[1]
redis:del(redis_key)
}
}
Expand Down Expand Up @@ -589,7 +597,8 @@ Return 429 code.
local redis = require('resty.redis'):new()
redis:connect(redis_host, redis_port)
redis:select(1)
redis:del("fixed_window_test9")
local redis_key = redis:keys('*_fixed_window_test9')[1]
redis:del(redis_key)
}
}
Expand Down Expand Up @@ -667,7 +676,8 @@ Return 200 code.
local redis = require('resty.redis'):new()
redis:connect(redis_host, redis_port)
redis:select(1)
redis:del("connections_test10")
local redis_key = redis:keys('*_connections_test10')[1]
redis:del(redis_key)
}
}
Expand Down Expand Up @@ -728,7 +738,8 @@ Return 200 code.
local redis = require('resty.redis'):new()
redis:connect(redis_host, redis_port)
redis:select(1)
redis:del("leaky_bucket_test11")
local redis_key = redis:keys('*_leaky_bucket_test11')[1]
redis:del(redis_key)
}
}
Expand Down Expand Up @@ -1065,7 +1076,9 @@ so only the third call returns 429.
local redis = require('resty.redis'):new()
redis:connect(redis_host, redis_port)
redis:select(1)
redis:del("fixed_window_test17_1", "fixed_window_test17_2")
local redis_key1 = redis:keys('*_fixed_window_test17_1')[1]
local redis_key2 = redis:keys('*_fixed_window_test17_2')[1]
redis:del(redis_key1, redis_key2)
}
}
Expand Down Expand Up @@ -1153,7 +1166,9 @@ so only the third call returns 429.
local redis = require('resty.redis'):new()
redis:connect(redis_host, redis_port)
redis:select(1)
redis:del("fixed_window_localhost/test18_1", "fixed_window_localhost/test18_2")
local redis_key1 = redis:keys('*_fixed_window_localhost/test18_1')[1]
local redis_key2 = redis:keys('*_fixed_window_localhost/test18_2')[1]
redis:del(redis_key1, redis_key2)
}
}
Expand Down

0 comments on commit 396f259

Please sign in to comment.