Liveness and readiness probes
If you want to test the readiness and the liveness of nevisProxy, you can use the Lua filter (LuaFilter). The sample code in the following code block illustrates how to configure two Lua filters for livenes or readiness probes within nevisProxy. The name of the two configured Lua filters is LivenessLuaFilter and ReadinessLuaFilter.
You find this example in the delivered nevisproxy package under: /opt/nevisproxy/examples/various/LuaFilter_liveness_and_readiness_probe.example
Readiness and Liveness Probes with the LuaFilter
<filter>
<filter-name>LivenessLuaFilter</filter-name>
<filter-class>ch::nevis::isiweb4::filter::lua::LuaFilter</filter-class>
<init-param>
<param-name>Script.InputHeaderFunctionName</param-name>
<param-value>inputHeaders</param-value>
</init-param>
<init-param>
<param-name>Script</param-name>
<param-value>
function inputHeaders(req, resp)
resp:setHeader("Content-Type", "application/json")
resp:setBody("{ \"status\" : \"UP\" }")
resp:send(200)
end
</param-value>
</init-param>
</filter>
<filter>
<filter-name>ReadinessLuaFilter</filter-name>
<filter-class>ch::nevis::isiweb4::filter::lua::LuaFilter</filter-class>
<init-param>
<param-name>Script.InputHeaderFunctionName</param-name>
<param-value>inputHeaders</param-value>
</init-param>
<init-param>
<param-name>Script</param-name>
<param-value>
package.path = package.path .. ";@PKG_VAR@/@PKG_INSTANCE@/lib/?.lua"
local GlobalStore = require "GlobalStore"
local databaseServlets = { "MySQLSessionStoreServlet1", "MySQLSessionStoreServlet2" }
local databasePingName = "DatabasePing"
local backendsServlets = { "HttpConnectorServlet1", "HttpConnectorServlet2" }
function testDatabaseServlets(req)
local tracer = req:getTracer()
local ret = true
for i,servlet in ipairs(databaseServlets) do
tracer:debug("Testing servlet '" .. servlet .. "'")
local store = GlobalStore:new(servlet)
local value = store:get(databasePingName)
if not value then
store:set(databasePingName, "OK", 3600)
value = store:get(databasePingName)
end
if value ~= "OK" then
tracer:error("The servlet '" .. servlet .. "' seems to be down")
ret = false;
else
tracer:debug("Servlet '" .. servlet .. "' is up and running")
end
end
return ret
end
function testBackends(req)
local tracer = req:getTracer()
local ret = true
for i,servlet in ipairs(backendsServlets) do
tracer:debug("Testing servlet '" .. servlet .. "'")
local pingRequest = nevis.filter.lua.request.new()
pingRequest:setRequestUri("/ping")
pingRequest:setMethod("GET")
local pingResponse = nevis.filter.lua.response.new()
local dispatcher = req:getDispatcher(servlet)
dispatcher:forward(pingRequest, pingResponse)
local pingStatusCode = pingResponse:getStatus()
if pingStatusCode ~= 200 then
tracer:error("The servlet '" .. servlet .. "' seems to be down")
ret = false;
else
tracer:debug("Servlet '" .. servlet .. "' is up and running")
end
end
return ret
end
function inputHeaders(req, resp)
local tracer = req:getTracer()
local dbReady
local dbackendReady
if pcall(function()
dbReady = testDatabaseServlets(req)
dbackendReady = testBackends(req)
end)
then
resp:setHeader("Content-Type", "application/json")
if not dbReady then
resp:setBody("{ \"status\" : \"DOWN\" }")
resp:send(503)
elseif not dbackendReady then
resp:setBody("{ \"status\" : \"DOWN\" }")
resp:send(503)
else
resp:setBody("{ \"status\" : \"UP\" }")
resp:send(200)
end
else
tracer:notice("An exception occured")
resp:setHeader("Content-Type", "application/json")
resp:setBody("{ \"status\" : \"DOWN\" }")
resp:send(503)
end
end
</param-value>
</init-param>
</filter>
- The LivenessLuaFilter returns the status code "200" to the frontend if the proxy is alive. If the LivenessLuaFilter is not triggered, the proxy is not alive.
- The ReadinessLuaFilter returns the status code "200" if the configured backends and the MySQLSessionStoreServlet (in the LuaFilter) are up and running ("ready").
In the sample code, the ReadinessLuaFilter first checks the MySQLSessionStoreServlets "MySQLSessionStoreServlet1" and "MySQLSessionStoreServlet2" by trying to add an entry to both servlets. To avoid too many update calls, the entry is added once per hour. The ReadinessLuaFilter also checks the HttpConnectorServlets "HttpConnectorServlet1" and "HttpConnectorServlet2", by calling the URL "/ping". Note that "/ping" is just an example. The correct URL depends on the backend itself.
To map both LuaFilters to a URL, and to ensure that the proxy will process the requests, you can place a DefaultServlet at the end of the filter chain. This servlet will never be reached, but this is no problem, as the LuaFilters will in any case send an answer to the frontend.