Skip to content

Commit

Permalink
feat: support setting function modules for xrpc (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlinsRan authored Sep 25, 2024
1 parent e516475 commit 00989f8
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 5 deletions.
21 changes: 17 additions & 4 deletions lib/resty/healthcheck.lua
Original file line number Diff line number Diff line change
Expand Up @@ -890,12 +890,14 @@ end
-- Runs a single healthcheck probe
function checker:run_single_check(ip, port, hostname, hostheader)
if self.checks.active.type == "xrpc" then
local ok, status = self.checks.active.xrpc_handler({
local handler = self.checks.active.xrpc_handler
local node = {
host = ip,
port = port,
domain = hostname,
}, self.xrpc_conf)

}
local conf = self.checks.active.xrpc_conf
local ok, status = handler(node, conf)
if not ok then
return self:report_failure(ip, port, hostname, "active")
end
Expand Down Expand Up @@ -1294,6 +1296,8 @@ local function fill_in_settings(opts, defaults, ctx)
if type(v) == "table" then
if default[1] then -- do not recurse on arrays
obj[k] = v
elseif default == NO_DEFAULT then
obj[k] = deepcopy(v)
else
ctx[#ctx + 1] = k
obj[k] = fill_in_settings(v, default, ctx)
Expand Down Expand Up @@ -1326,8 +1330,9 @@ local defaults = {
concurrency = 10,
http_path = "/",
https_verify_certificate = true,
xrpc_function_module = NO_DEFAULT,
xrpc_handler = NO_DEFAULT,
xrpc_conf = {},
xrpc_conf = NO_DEFAULT,
healthy = {
interval = 0, -- 0 = disabled by default
http_statuses = { 200, 302 },
Expand Down Expand Up @@ -1455,6 +1460,14 @@ function _M.new(opts)
end

if self.checks.active.type == "xrpc" then
local module = self.checks.active.xrpc_function_module
if module then
local ok, handler = pcall(require, module)
if not ok then
return nil, "failed to load xrpc handler module: " .. handler
end
self.checks.active.xrpc_handler = handler
end
assert(self.checks.active.xrpc_handler, "required option 'checks.active.xrpc_handler' is missing")
assert(self.checks.active.unhealthy.failures < 255, "checks.active.unhealthy.tcp_failures must be at most 254")
end
Expand Down
145 changes: 144 additions & 1 deletion t/report_xrpc_status.t
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ workers(1);
my $pwd = cwd();

our $HttpConfig = qq{
lua_package_path "$pwd/lib/?.lua;;";
lua_package_path "$pwd/lib/?.lua;$pwd/t/?.lua;;";
lua_shared_dict test_shm 8m;
lua_shared_dict my_worker_events 8m;
};
Expand Down Expand Up @@ -499,3 +499,146 @@ event: target status '(127.0.0.1:2119)' from 'true' to 'false'
healthy SUCCESS increment (1/2)
healthy SUCCESS increment (2/2)
event: target status '(127.0.0.1:2119)' from 'false' to 'true'



=== TEST 8: start xrpc healthcheck with xrpc_conf
--- http_config eval
qq{
$::HttpConfig

server {
listen 2119;
location = /status {
return 200;
}
}
}
--- config
location = /t {
content_by_lua_block {
local we = require "resty.worker.events"
assert(we.configure{ shm = "my_worker_events", interval = 0.1 })
local healthcheck = require("resty.healthcheck")
local checker = healthcheck.new({
name = "testing",
shm_name = "test_shm",
type = "xrpc",
checks = {
active = {
healthy = {
interval = 0.5, -- we don't want active checks
successes = 2,
},
unhealthy = {
interval = 0.5, -- we don't want active checks
failures = 2,
},
xrpc_conf = {
timeout = 1000,
},
xrpc_handler = function(node, conf)
ngx.log(ngx.INFO, "node.host: ", node.host, ", node.port: ", node.port)
ngx.log(ngx.INFO, "conf.timeout: ", conf.timeout)
end
},
},
})
ngx.sleep(0.1) -- wait for initial timers to run once
checker:add_target("127.0.0.1", 2119, nil, true)
ngx.sleep(1)
}
}
--- request
GET /t
--- timeout: 10
--- error_log
node.host: 127.0.0.1, node.port: 2119
conf.timeout: 1000



=== TEST 9: start xrpc healthcheck with xrpc_function_module
--- http_config eval
qq{
$::HttpConfig

lua_shared_dict request_counters 1m;

server {
listen 2119;

location /status {
content_by_lua_block {
local uri = ngx.var.request_uri
local counter = ngx.shared.request_counters

counter:incr(uri, 1, 0)

local current_count = counter:get(uri) or 0

if current_count < 4 or current_count > 8 then
ngx.status = 200
ngx.say("OK")
else
ngx.status = 500
ngx.say("ERROR")
end
}
}
}
}
--- config
location = /t {
content_by_lua_block {
local we = require "resty.worker.events"
assert(we.configure{ shm = "my_worker_events", interval = 0.1 })
local healthcheck = require("resty.healthcheck")
local checker, err = healthcheck.new({
name = "testing",
shm_name = "test_shm",
type = "xrpc",
checks = {
active = {
healthy = {
interval = 0.5, -- we don't want active checks
successes = 2,
},
unhealthy = {
interval = 0.5, -- we don't want active checks
failures = 2,
},
xrpc_function_module = "util.http_handler",
},
},
})
if not checker then
ngx.log(ngx.ERR, "failed to create healthcheck: ", err)
return
end
ngx.sleep(0.1) -- wait for initial timers to run once
checker:add_target("127.0.0.1", 2119, nil, true)
ngx.sleep(0.5)
ngx.say(checker:get_target_status("127.0.0.1", 2119, nil)) -- true
ngx.sleep(3.1)
ngx.say(checker:get_target_status("127.0.0.1", 2119, nil)) -- false
ngx.sleep(4.2)
ngx.say(checker:get_target_status("127.0.0.1", 2119, nil)) -- true
}
}
--- request
GET /t
--- timeout: 10
--- response_body
true
false
true
--- error_log
checking healthy targets: nothing to do
checking unhealthy targets: nothing to do
unhealthy XRPC increment (1/2) for '(127.0.0.1:2119)'
unhealthy XRPC increment (2/2) for '(127.0.0.1:2119)'
event: target status '(127.0.0.1:2119)' from 'true' to 'false'
healthy SUCCESS increment (1/2)
healthy SUCCESS increment (2/2)
event: target status '(127.0.0.1:2119)' from 'false' to 'true'
18 changes: 18 additions & 0 deletions t/util/http_handler.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
local http = require('resty.http')
local json = require('cjson')

return function (node, conf)
ngx.log(ngx.INFO, "http_handler node: ", json.encode(node), " conf: ", json.encode(conf))
conf = conf or {}
local httpc = http.new()
local uri = "http://" .. node.host .. ":" .. node.port
local res, err = httpc:request_uri(uri, {
method = conf.method or "GET",
path = conf.path or "/status",
})
if not res then
ngx.log(ngx.ERR, "failed to request: ", err)
return false
end
return true, res.status
end

0 comments on commit 00989f8

Please sign in to comment.