When restarting or reloading a instance configured resty-healthcheck most of the time the following error occurs:
local _M = {}
local origins = {}
local healthchecker = {}
[...]
function _M.init_worker()
-- Attention: Both modules must be required in init_worker().
-- If one of those is required in global module space (e.g. Nginx init) resty.worker.events fails to manage it's internal _callback list
local we = require "resty.worker.events"
local hc = require "resty.healthcheck"
-- worker events
-- add dummy handler
local handler = function(target, eventname, sourcename, pid)
end
we.register(handler)
-- configure worker events
local ok, err = we.configure{ shm = "worker_events", interval = 0.1 }
if not ok then
ngx.log(ngx.ERR, "Failed to configure worker events: ", err)
return
end
-- 8< --
-- All code below is repeated for each handled domain.
-- At failing instance: 3x
-- >8 --
-- upstream health checks
-- domain: domain1.tld
-- init checker
local checker = hc.new({
name = "domain1.tld",
shm_name = "healthchecks",
type = "https",
checks = {
active = {
http_path = '/',
healthy = {
interval = 10,
successes = 1,
},
unhealthy = {
interval = 5,
http_statuses = { 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410,
410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420,
420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430,
431, 451,
500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510,
511 },
tcp_failures = 2,
http_failures = 2,
timeouts = 2,
}
},
passive = {
healthy = {
successes = 1,
},
unhealthy = {
http_statuses = { 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410,
410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420,
420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430,
431, 451,
500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510,
511 },
tcp_failures = 2,
http_failures = 2,
timeouts = 2,
}
}
}
})
-- clear data to avoid broken syncronisation between health checker and balancer
-- on nginx reload healtchecker keeps state and balancer loose it
-- checker:clear()
-- ^^ not necessary anymore because of workaround below
-- add event handler for checker
local handler = function(target, eventname, sourcename, pid)
if not target then
return
end
local domain = target.hostname
local origin_host = target.ip
if eventname == checker.events.remove then
-- a target was removed
local ok, err = pcall(function () origins[domain][1]:delete(origin_host) end)
if not ok then
ngx.log(ngx.WARN, "Deleting balancer node ", origin_host, " from domain: ", domain, " failed: ", err)
else
ngx.log(ngx.DEBUG, "Balancer node ", origin_host, " of domain: ", domain, " deleted")
end
elseif eventname == checker.events.healthy then
-- target changed state, or was added
local ok, err = pcall(function () origins[domain][1]:set(origin_host, 1) end)
if not ok then
ngx.log(ngx.WARN, "Setting balancer node ", origin_host, " for domain: ", domain, " failed: ", err)
else
ngx.log(ngx.DEBUG, "Balancer node ", origin_host, " for domain: ", domain, " added")
end
elseif eventname == checker.events.unhealthy then
-- target changed state, or was added
local ok, err = pcall(function () origins[domain][1]:delete(origin_host) end)
if not ok then
ngx.log(ngx.WARN, "Balancer delete for domain: ", domain, " failed: ", err)
else
ngx.log(ngx.DEBUG, "Balancer node ", origin_host, " of domain: ", domain, " deleted")
end
end
end
we.register(handler)
-- add origin nodes
-- special handling for nginx relaod
-- health checker keeps state from previous instance, balancer not.
-- we use the previous known state to resend healthy and unhealthy events to resync balancer node states
-- this avoids the also possible use of checker:clear to reset the internal health states. The advantage of this
-- approach is, that we don't lose the knowledge about unhealthy hosts.
local healthy, err = checker:get_target_status("192.0.2.1", 443)
if not err then
checker:set_target_status("192.0.2.1", 443, healthy)
end
-- add new nodes in case of newly configured origins after reload or just a normal (re)start of nginx
local ok, err = checker:add_target("192.0.2.1", 443, "domain1.tld", true)
if err then
ngx.log(ngx.ERR, 'Error adding target 192.0.2.1 to healthchecker domain1.tld: ', err)
end
-- store in module wide register
healthchecker["domain1.tld"] = checker
[...]
end