-- -- Licensed to the Apache Software Foundation (ASF) under one or more -- contributor license agreements. See the NOTICE file distributed with -- this work for additional information regarding copyright ownership. -- The ASF licenses this file to You under the Apache License, Version 2.0 -- (the "License"); you may not use this file except in compliance with -- the License. You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. -- local math = require "math" local abs = math.abs local max = math.max local ngx_now = ngx.now local ngx_null = ngx.null local tonumber = tonumber local _M = {version = 0.1} -- the "commit" argument controls whether should we record the event in shm. function _M.incoming(self, red, key, commit) local rate = self.rate local now = ngx_now() * 1000 key = "limit_req" .. ":" .. key local excess_key = key .. "excess" local last_key = key .. "last" local excess, err = red:get(excess_key) if err then return nil, err end local last, err = red:get(last_key) if err then return nil, err end if excess ~= ngx_null and last ~= ngx_null then excess = tonumber(excess) last = tonumber(last) local elapsed = now - last excess = max(excess - rate * abs(elapsed) / 1000 + 1000, 0) if excess > self.burst then return nil, "rejected" end else excess = 0 end if commit then local ok local err ok, err = red:set(excess_key, excess) if not ok then return nil, err end ok, err = red:set(last_key, now) if not ok then return nil, err end end -- return the delay in seconds, as well as excess return excess / rate, excess / 1000 end return _M