Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow to set custom timeout for route #4340

Merged
merged 5 commits into from
Jun 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions apisix/balancer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,19 @@ end


-- set_balancer_opts will be called in balancer phase and before any tries
local function set_balancer_opts(ctx)
local function set_balancer_opts(route, ctx)
local up_conf = ctx.upstream_conf
if up_conf.timeout then
local timeout = up_conf.timeout

-- If the matched route has timeout config, prefer to use the route config.
local timeout = nil
if route and route.value and route.value.timeout then
timeout = route.value.timeout
else
if up_conf.timeout then
timeout = up_conf.timeout
end
end
if timeout then
local ok, err = set_timeouts(timeout.connect, timeout.send,
timeout.read)
if not ok then
Expand Down Expand Up @@ -252,7 +261,7 @@ function _M.run(route, ctx)
server = ctx.picked_server
ctx.picked_server = nil

set_balancer_opts(ctx)
set_balancer_opts(route, ctx)

else
-- retry
Expand Down
22 changes: 13 additions & 9 deletions apisix/schema_def.lua
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,17 @@ local desc_def = {
}


local timeout_def = {
type = "object",
properties = {
connect = {type = "number", exclusiveMinimum = 0},
send = {type = "number", exclusiveMinimum = 0},
read = {type = "number", exclusiveMinimum = 0},
},
required = {"connect", "send", "read"},
}


local health_checker = {
type = "object",
properties = {
Expand Down Expand Up @@ -342,15 +353,7 @@ local upstream_schema = {
type = "integer",
minimum = 0,
},
timeout = {
type = "object",
properties = {
connect = {type = "number", exclusiveMinimum = 0},
send = {type = "number", exclusiveMinimum = 0},
read = {type = "number", exclusiveMinimum = 0},
},
required = {"connect", "send", "read"},
},
timeout = timeout_def,
tls = {
type = "object",
properties = {
Expand Down Expand Up @@ -491,6 +494,7 @@ _M.route = {
minItems = 1,
uniqueItems = true,
},
timeout = timeout_def,
vars = {
type = "array",
},
Expand Down
10 changes: 8 additions & 2 deletions docs/en/latest/admin-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ Note: When the `Admin API` is enabled, it will occupy the API prefixed with `/ap
| service_id | False | Service | Binded Service configuration, see [Service](architecture-design/service.md) for more | |
| plugin_config_id | False, can't be used with `script` | Plugin | Binded plugin config object, see [Plugin Config](architecture-design/plugin-config.md) for more | |
| labels | False | Match Rules | Key/value pairs to specify attributes | {"version":"v2","build":"16","env":"production"} |
| timeout | False | Auxiliary | Set the upstream timeout for connecting, sending and receiving messages of the route. This option will overwrite the [timeout](#upstream) option which set in upstream configuration. | {"connect": 3, "send": 3, "read": 3} |
| enable_websocket | False | Auxiliary | enable `websocket`(boolean), default `false`. | |
| status | False | Auxiliary | enable this route, default `1`. | `1` to enable, `0` to disable |
| create_time | False | Auxiliary | epoch timestamp in second, will be created automatically if missing | 1602883670 |
Expand All @@ -117,6 +118,11 @@ Config Example:
"vars": [["http_user", "==", "ios"]], # A list of one or more `[var, operator, val]` elements
"upstream_id": "1", # upstream id, recommended
"upstream": {}, # upstream, not recommended
"timeout": { # Set the upstream timeout for connecting, sending and receiving messages of the route.
"connect": 3,
"send": 3,
"read": 3
},
"filter_func": "", # User-defined filtering function
}
```
Expand Down Expand Up @@ -539,7 +545,7 @@ In addition to the basic complex equalization algorithm selection, APISIX's Upst
|key |optional|This option is only valid if the `type` is `chash`. Find the corresponding node `id` according to `hash_on` and `key`. When `hash_on` is set as `vars`, `key` is the required parameter, for now, it support nginx built-in variables like `uri, server_name, server_addr, request_uri, remote_port, remote_addr, query_string, host, hostname, arg_***`, `arg_***` is arguments in the request line, [Nginx variables list](http://nginx.org/en/docs/varindex.html). When `hash_on` is set as `header`, `key` is the required parameter, and `header name` is customized. When `hash_on` is set to `cookie`, `key` is the required parameter, and `cookie name` is customized. When `hash_on` is set to `consumer`, `key` does not need to be set. In this case, the `key` adopted by the hash algorithm is the `consumer_name` authenticated. If the specified `hash_on` and `key` can not fetch values, it will be fetch `remote_addr` by default.|
|checks |optional|Configure the parameters of the health check. For details, refer to [health-check](health-check.md).|
|retries |optional|Pass the request to the next upstream using the underlying Nginx retry mechanism, the retry mechanism is enabled by default and set the number of retries according to the number of available backend nodes. If `retries` option is explicitly set, it will override the default value. `0` means disable retry mechanism.|
|timeout |optional| Set the timeout for connection, sending and receiving messages. |
|timeout |optional| Set the timeout for connecting, sending and receiving messages. |
|name |optional|Identifies upstream names|
|desc |optional|upstream usage scenarios, and more.|
|pass_host |optional| `host` option when the request is sent to the upstream, can be one of [`pass`, `node`, `rewrite`], the default option is `pass`. `pass`: Pass the client's host transparently to the upstream; `node`: Use the host configured in the node of `upstream`; `rewrite`: Use the value of the configuration `upstream_host`.|
Expand Down Expand Up @@ -577,7 +583,7 @@ This feature requires APISIX to run on [APISIX-OpenResty](../how-to-build.md#6-b
{
"id": "1", # id
"retries": 1, # retry times
"timeout": { # Set the timeout for connection, sending and receiving messages.
"timeout": { # Set the timeout for connecting, sending and receiving messages.
"connect":15,
"send":15,
"read":15,
Expand Down
6 changes: 6 additions & 0 deletions docs/zh/latest/admin-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ Admin API 是为 Apache APISIX 服务的一组 API,我们可以将参数传递
| vars | 可选 | 匹配规则 | 由一个或多个`{var, operator, val}`元素组成的列表,类似这样:`{{var, operator, val}, {var, operator, val}, ...}}`。例如:`{"arg_name", "==", "json"}`,表示当前请求参数 `name` 是 `json`。这里的 `var` 与 Nginx 内部自身变量命名是保持一致,所以也可以使用 `request_uri`、`host` 等。更多细节请参考[lua-resty-expr](https://github.com/api7/lua-resty-expr) | {{"arg_name", "==", "json"}, {"arg_age", ">", 18}} |
| filter_func | 可选 | 匹配规则 | 用户自定义的过滤函数。可以使用它来实现特殊场景的匹配要求实现。该函数默认接受一个名为 vars 的输入参数,可以用它来获取 Nginx 变量。 | function(vars) return vars["arg_name"] == "json" end |
| labels | 可选 | 匹配规则 | 标识附加属性的键值对 | {"version":"v2","build":"16","env":"production"} |
| timeout | 可选 | 辅助 | 为 route 设置 upstream 的连接、发送消息、接收消息的超时时间。这个配置将会覆盖在 upstream 中 配置的 [timeout](#upstream) 选项 | {"connect": 3, "send": 3, "read": 3} |
| enable_websocket | 可选 | 辅助 | 是否启用 `websocket`(boolean), 缺省 `false`. | |
| status | 可选 | 辅助 | 是否启用此路由, 缺省 `1`。 | `1` 表示启用,`0` 表示禁用 |
| create_time | 可选 | 辅助 | 单位为秒的 epoch 时间戳,如果不指定则自动创建 | 1602883670 |
Expand All @@ -118,6 +119,11 @@ route 对象 json 配置内容:
"vars": [["http_user", "==", "ios"]], # 由一个或多个 [var, operator, val] 元素组成的列表
"upstream_id": "1", # upstream 对象在 etcd 中的 id ,建议使用此值
"upstream": {}, # upstream 信息对象,建议尽量不要使用
"timeout": { # 为 route 设置 upstream 的连接、发送消息、接收消息的超时时间。
"connect": 3,
"send": 3,
"read": 3
},
"filter_func": "", # 用户自定义的过滤函数,非必填
}
```
Expand Down
37 changes: 37 additions & 0 deletions t/admin/routes2.t
Original file line number Diff line number Diff line change
Expand Up @@ -650,3 +650,40 @@ GET /t
{"error_msg":"failed to fetch plugin config info by plugin config id [not_found], response code: 404"}
--- no_error_log
[error]



=== TEST 18: valid route with timeout
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to add test to t/node/timeout-upstream.t

--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"methods": ["GET"],
"upstream": {
"nodes": {
"127.0.0.1:8080": 1
},
"type": "roundrobin"
},
"timeout": {
"connect": 3,
"send": 3,
"read": 3
},
"uri": "/index.html"
}]]
)

ngx.status = code
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- no_error_log
[error]
55 changes: 55 additions & 0 deletions t/node/timeout-upstream.t
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,58 @@ GET /sleep1
qr/504 Gateway Time-out/
--- error_log
timed out) while reading response header from upstream



=== TEST 3: set custom timeout for route(overwrite upstream timeout)
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"methods": ["GET"],
"timeout": {
"connect": 0.5,
"send": 0.5,
"read": 0.5
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin",
"timeout": {
"connect": 2,
"send": 2,
"read": 2
}
},
"uri": "/sleep1"
}]]
)

if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
--- no_error_log
[error]



=== TEST 4: hit routes (timeout)
--- request
GET /sleep1
--- error_code: 504
--- response_body eval
qr/504 Gateway Time-out/
--- error_log
timed out) while reading response header from upstream