Files
2026-07-13 12:32:21 +08:00

136 lines
3.6 KiB
Lua

local declarative = require "kong.db.declarative"
local constants = require "kong.constants"
local ngx = ngx
local ngx_log = ngx.log
local ngx_NOTICE = ngx.NOTICE
local ngx_DEBUG = ngx.DEBUG
local tonumber = tonumber
local kong = kong
local fmt = string.format
local get_current_hash = declarative.get_current_hash
local worker_count = ngx.worker.count()
local kong_shm = ngx.shared.kong
local is_dbless = kong.configuration.database == "off"
local is_control_plane = kong.configuration.role == "control_plane"
local PLUGINS_REBUILD_COUNTER_KEY = constants.PLUGINS_REBUILD_COUNTER_KEY
local ROUTERS_REBUILD_COUNTER_KEY = constants.ROUTERS_REBUILD_COUNTER_KEY
local DECLARATIVE_EMPTY_CONFIG_HASH = constants.DECLARATIVE_EMPTY_CONFIG_HASH
local KONG_STATUS_READY = "kong:status:ready"
local function is_dbless_ready(router_rebuilds, plugins_iterator_rebuilds)
if router_rebuilds < worker_count then
return false, fmt("router builds not yet complete, router ready"
.. " in %d of %d workers", router_rebuilds, worker_count)
end
if plugins_iterator_rebuilds < worker_count then
return false, fmt("plugins iterator builds not yet complete, "
.. "plugins iterator ready in %d of %d workers",
plugins_iterator_rebuilds, worker_count)
end
local current_hash = get_current_hash()
if not current_hash then
return false, "no configuration available (configuration hash is not initialized)"
end
if current_hash == DECLARATIVE_EMPTY_CONFIG_HASH then
return false, "no configuration available (empty configuration present)"
end
return true
end
local function is_traditional_ready(router_rebuilds, plugins_iterator_rebuilds)
-- traditional mode builds router from database once inside `init` phase
if router_rebuilds == 0 then
return false, "router builds not yet complete"
end
if plugins_iterator_rebuilds == 0 then
return false, "plugins iterator build not yet complete"
end
return true
end
--[[
Checks if Kong is ready to serve.
@return boolean indicating if Kong is ready to serve.
@return string|nil an error message if Kong is not ready, or nil otherwise.
--]]
local function is_ready()
local ok = kong.db:connect() -- for dbless, always ok
if not ok then
return false, "failed to connect to database"
end
kong.db:close()
if is_control_plane then
return true
end
local router_rebuilds =
tonumber(kong_shm:get(ROUTERS_REBUILD_COUNTER_KEY)) or 0
local plugins_iterator_rebuilds =
tonumber(kong_shm:get(PLUGINS_REBUILD_COUNTER_KEY)) or 0
local err
-- full check for dbless mode
if is_dbless then
ok, err = is_dbless_ready(router_rebuilds, plugins_iterator_rebuilds)
else
ok, err = is_traditional_ready(router_rebuilds, plugins_iterator_rebuilds)
end
return ok, err
end
return {
["/status/ready"] = {
GET = function(self, dao, helpers)
local ready = kong_shm:get(KONG_STATUS_READY)
if ready == nil then
kong_shm:set(KONG_STATUS_READY, true)
end
if ready == false then
return kong.response.exit(503, { message = "draining" })
end
local ok, err = is_ready()
if ok then
ngx_log(ngx_DEBUG, "ready for proxying")
return kong.response.exit(200, { message = "ready" })
else
ngx_log(ngx_NOTICE, "not ready for proxying: ", err)
return kong.response.exit(503, { message = err })
end
end,
POST = function(self, dao, helpers)
if self.params and self.params.status == "draining" then
kong_shm:set(KONG_STATUS_READY, false)
return kong.response.exit(204)
end
return kong.response.exit(400)
end
},
}