diff --git a/CHANGELOG.md b/CHANGELOG.md index bd698c5af..96722b430 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - The `scope` of the Rate Limit policy is `service` by default [PR #704](https://github.com/3scale/apicast/pull/704) - Decoded JWTs are now exposed in the policies context by the APIcast policy [PR #718](https://github.com/3scale/apicast/pull/718) - Upgraded OpenResty to 1.13.6.2, uses OpenSSL 1.1 [PR #733](https://github.com/3scale/apicast/pull/733) +- Use forked `resty.limit.count` that uses increments instead of decrements [PR #758](https://github.com/3scale/apicast/pull/758) ### Fixed diff --git a/gateway/src/apicast/policy/rate_limit/rate_limit.lua b/gateway/src/apicast/policy/rate_limit/rate_limit.lua index 2b93827a3..9472c5c54 100644 --- a/gateway/src/apicast/policy/rate_limit/rate_limit.lua +++ b/gateway/src/apicast/policy/rate_limit/rate_limit.lua @@ -3,7 +3,7 @@ local _M = policy.new('Rate Limit Policy') local resty_limit_conn = require('resty.limit.conn') local resty_limit_req = require('resty.limit.req') -local resty_limit_count = require('resty.limit.count') +local resty_limit_count = require('resty.limit.count-inc') local ngx_semaphore = require "ngx.semaphore" local limit_traffic = require "resty.limit.traffic" diff --git a/gateway/src/resty/limit/count-inc.lua b/gateway/src/resty/limit/count-inc.lua new file mode 100644 index 000000000..f19e3012e --- /dev/null +++ b/gateway/src/resty/limit/count-inc.lua @@ -0,0 +1,60 @@ +-- This file applies a patch from +-- https://github.com/3scale/lua-resty-limit-traffic/commit/c53f2240e953a9656580dbafcc142363ab063100 +-- It can be removed when https://github.com/openresty/lua-resty-limit-traffic/pull/34 is merged and released. + +local _M = {} +local resty_limit_count = require('resty.limit.count') +local setmetatable = setmetatable + +local mt = { + __index = _M +} + +function _M.new(...) + return setmetatable(resty_limit_count.new(...), mt) +end + +function _M.incoming(self, key, commit) + local dict = self.dict + local limit = self.limit + local window = self.window + + local count, err + + if commit then + count, err = dict:incr(key, 1, 0, window) + + if not count then + return nil, err + end + else + count = (dict:get(key) or 0) + 1 + end + + if count > limit then + return nil, "rejected" + end + + return 0, limit - count +end + +-- uncommit remaining and return remaining value +function _M.uncommit(self, key) + assert(key) + local dict = self.dict + local limit = self.limit + + local count, err = dict:incr(key, -1) + if not count then + if err == "not found" then + count = 0 + else + return nil, err + end + end + + return limit - count +end + +return setmetatable(_M, { __index = resty_limit_count }) + diff --git a/spec/policy/rate_limit/rate_limit_spec.lua b/spec/policy/rate_limit/rate_limit_spec.lua index ab0f1d06b..282d631d1 100644 --- a/spec/policy/rate_limit/rate_limit_spec.lua +++ b/spec/policy/rate_limit/rate_limit_spec.lua @@ -149,7 +149,7 @@ describe('Rate limit policy', function() redis:connect(redis_host, redis_port) redis:select(1) local fixed_window = redis:get('fixed_window_test3') - assert.equal('-1', fixed_window) + assert.equal('2', fixed_window) end) it('rejected (count), name_type is liquid', function() @@ -169,7 +169,7 @@ describe('Rate limit policy', function() redis:connect(redis_host, redis_port) redis:select(1) local fixed_window = redis:get('fixed_window_test3') - assert.equal('-1', fixed_window) + assert.equal('2', fixed_window) end) it('rejected (count), name_type is liquid, ngx variable', function() @@ -188,7 +188,7 @@ describe('Rate limit policy', function() redis:connect(redis_host, redis_port) redis:select(1) local fixed_window = redis:get('fixed_window_test3') - assert.equal('-1', fixed_window) + assert.equal('2', fixed_window) end) it('delay (conn)', function()