Skip to content
Merged
14 changes: 13 additions & 1 deletion apisix/plugins/limit-conn.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ local limit_conn = require("apisix.plugins.limit-conn.ini
local redis_schema = require("apisix.utils.redis-schema")
local policy_to_additional_properties = redis_schema.schema
local plugin_name = "limit-conn"

local workflow = require("apisix.plugins.workflow")


local schema = {
Expand Down Expand Up @@ -90,5 +90,17 @@ function _M.log(conf, ctx)
return limit_conn.decrease(conf, ctx)
end

function _M.workflow_handler()
workflow.register(plugin_name,
function (conf) -- schema validation
return core.schema.check(schema, conf)
end,
function (conf, ctx) -- handler run in access phase
return limit_conn.increase(conf, ctx, plugin_name, 1)
end,
function (conf, ctx) -- log_handler run in log phase
return limit_conn.decrease(conf, ctx, plugin_name, 1)
end)
end

return _M
6 changes: 3 additions & 3 deletions apisix/plugins/limit-count.lua
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ end

function _M.workflow_handler()
workflow.register(plugin_name,
function (conf, ctx)
return limit_count.rate_limit(conf, ctx, plugin_name, 1)
end,
function (conf)
return limit_count.check_schema(conf)
end,
function (conf, ctx)
return limit_count.rate_limit(conf, ctx, plugin_name, 1)
Comment thread
nic-chen marked this conversation as resolved.
end)
end

Expand Down
48 changes: 38 additions & 10 deletions apisix/plugins/workflow.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
local core = require("apisix.core")
local expr = require("resty.expr.v1")
local ipairs = ipairs
local core = require("apisix.core")
local expr = require("resty.expr.v1")
local ipairs = ipairs
local setmetatable = setmetatable
local getmetatable = getmetatable

local schema = {
type = "object",
Expand Down Expand Up @@ -101,13 +103,15 @@ local support_action = {
}


function _M.register(plugin_name, handler, check_schema)
function _M.register(plugin_name, check_schema, access_handler, log_handler)
support_action[plugin_name] = {
handler = handler,
check_schema = check_schema
check_schema = check_schema,
handler = access_handler,
log_handler = log_handler
}
end


function _M.check_schema(conf)
local ok, err = core.schema.check(schema, conf)
if not ok then
Expand All @@ -116,10 +120,17 @@ function _M.check_schema(conf)

for idx, rule in ipairs(conf.rules) do
if rule.case then
local ok, err = expr.new(rule.case)
local expr, err = expr.new(rule.case)
if not ok then
return false, "failed to validate the 'case' expression: " .. err
end
local mt = getmetatable(rule)
if not mt then
mt = {}
mt.__index = mt
Comment thread
bzp2010 marked this conversation as resolved.
setmetatable(rule, mt)
end
mt.__expr = expr
end

local actions = rule.actions
Expand All @@ -143,12 +154,16 @@ end


function _M.access(conf, ctx)
for _, rule in ipairs(conf.rules) do
ctx._workflow_cache = ctx._workflow_cache or {}
for idx, rule in ipairs(conf.rules) do
local match_result = true
if rule.case then
local expr, _ = expr.new(rule.case)
match_result = expr:eval(ctx.var)
local expr = rule.__expr
Comment thread
bzp2010 marked this conversation as resolved.
if expr then
match_result = expr:eval(ctx.var)
end
end
ctx._workflow_cache[idx] = match_result
if match_result then
-- only one action is currently supported
local action = rule.actions[1]
Expand All @@ -157,5 +172,18 @@ function _M.access(conf, ctx)
end
end

function _M.log(conf, ctx)
for idx, rule in ipairs(conf.rules) do
local match_result = ctx._workflow_cache[idx]
if match_result then
-- only one action is currently supported
local action = rule.actions[1]
local log_handler = support_action[action[1]].log_handler
if log_handler then
Comment thread
bzp2010 marked this conversation as resolved.
return log_handler(action[2], ctx)
end
end
end
end

return _M
2 changes: 1 addition & 1 deletion docs/en/latest/plugins/workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ The `workflow` Plugin supports the conditional execution of user-defined actions
| ---------------------------- | ------------- | -------- | ------- | ------------ | ------------------------------------------------------------ |
| rules | array[object] | True | | | An array of one or more pairs of matching conditions and actions to be executed. |
| rules.case | array[array] | False | | | An array of one or more matching conditions in the form of [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list). For example, `{"arg_name", "==", "json"}`. |
| rules.actions | array[object] | True | | | An array of actions to be executed when a condition is successfully matched. Currently, the array only supports one action, and it should be either `return`, or `limit-count`. When the action is configured to be `return`, you can configure an HTTP status code to return to the client when the condition is matched. When the action is configured to be `limit-count`, you can configure all options of the [`limit-count`](./limit-count.md) plugin, except for `group`. |
| rules.actions | array[object] | True | | | An array of actions to be executed when a condition is successfully matched. Currently, the array only supports one action, and it should be either `return`, or `limit-count` or `limit-conn`. When the action is configured to be `return`, you can configure an HTTP status code to return to the client when the condition is matched. When the action is configured to be `limit-count`, you can configure all options of the [`limit-count`](./limit-count.md) plugin, except for `group`. When the action is configured to be `limit-conn`, you can configure all options of the [`limit-conn`](./limit-conn.md) plugin. |

## Examples

Expand Down
2 changes: 1 addition & 1 deletion docs/zh/latest/plugins/workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ description: workflow 插件支持根据给定的一组规则有条件地执行
| ------------- | ------ | ------ | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| rules | array[object] | 是 | | | 一对或多对匹配条件和要执行的操作组成的数组。 |
| rules.case | array[array] | 否 | | | 一个或多个匹配条件的数组,形式为 [lua-resty-expr](https://github.com/api7/lua-resty-expr#operator-list),例如 `{"arg_name", "==", "json"}`。 |
| rules.actions | array[object] | 是 | | | 条件匹配成功后要执行的操作的数组。目前数组只支持一个操作,必须是 `return` 或者 `limit-count`。当操作配置为 `return` 时,可以配置条件匹配成功时返回给客户端的 HTTP 状态码。当操作配置为 `limit-count` 时,可以配置 [`limit-count`](./limit-count.md) 插件除 `group` 之外的所有选项。 |
| rules.actions | array[object] | 是 | | | 条件匹配成功后要执行的操作的数组。目前数组只支持一个操作,必须是 `return` 或者 `limit-count`。当操作配置为 `return` 时,可以配置条件匹配成功时返回给客户端的 HTTP 状态码。当操作配置为 `limit-count` 时,可以配置 [`limit-count`](./limit-count.md) 插件除 `group` 之外的所有选项。当操作配置为 `limit-conn` 时,可以配置 [`limit-conn`](./limit-conn.md)。 |

## 示例

Expand Down
144 changes: 144 additions & 0 deletions t/plugin/workflow3.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
#
# 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.
#

BEGIN {
if ($ENV{TEST_NGINX_CHECK_LEAK}) {
$SkipReason = "unavailable for the hup tests";

} else {
$ENV{TEST_NGINX_USE_HUP} = 1;
undef $ENV{TEST_NGINX_USE_STAP};
}
}

use t::APISIX 'no_plan';

repeat_each(1);
no_long_string();
no_root_location();
no_shuffle();
add_block_preprocessor(sub {
my ($block) = @_;
my $port = $ENV{TEST_NGINX_SERVER_PORT};
my $config = $block->config // <<_EOC_;
location /access_root_dir {
content_by_lua_block {
local httpc = require "resty.http"
local hc = httpc:new()

local res, err = hc:request_uri('http://127.0.0.1:$port/limit_conn')
if res then
ngx.exit(res.status)
end
}
}

location /test_concurrency {
content_by_lua_block {
local reqs = {}
for i = 1, 10 do
reqs[i] = { "/access_root_dir" }
end
local resps = { ngx.location.capture_multi(reqs) }
for i, resp in ipairs(resps) do
ngx.say(resp.status)
end
}
}
_EOC_

$block->set_value("config", $config);
if (!$block->request) {
$block->set_value("request", "GET /t");
}
});

run_tests();


__DATA__

=== TEST 1: limit-conn
--- config
location /t {
content_by_lua_block {
local json = require("toolkit.json")
local t = require("lib.test_admin").test
local data = {
uri = "/*",
plugins = {
workflow = {
rules = {
{
case = {
{"uri", "==", "/limit_conn"}
},
actions = {
{
"limit-conn",
{
conn = 2,
burst = 1,
default_conn_delay = 0.1,
rejected_code = 503,
key = "remote_addr"
}
}
}
}
}
}
},
upstream = {
nodes = {
["127.0.0.1:1980"] = 1
},
type = "roundrobin"
}
}
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
json.encode(data)
)

if code >= 300 then
ngx.status = code
end

ngx.say(body)
}
}
--- response_body
passed



=== TEST 2: exceeding the burst
--- request
GET /test_concurrency
--- timeout: 10s
--- response_body
200
200
200
503
503
503
503
503
503
503
Loading