Skip to content

Instantly share code, notes, and snippets.

@lordnynex
Created January 10, 2017 00:21
Show Gist options
  • Save lordnynex/cbeb6f4d2580536aa58b632b637cd7b4 to your computer and use it in GitHub Desktop.
Save lordnynex/cbeb6f4d2580536aa58b632b637cd7b4 to your computer and use it in GitHub Desktop.
http {
lua_shared_dict healthchecks 1m;
upstream YOURAPP {
server 0.0.0.1; # just an invalid address as a place holder
balancer_by_lua_block {
local balancer = require "ngx.balancer"
-- well, usually we calculate the peer's host and port
-- according to some balancing policies instead of using
-- hard-coded values like below
local host = "127.0.0.2"
local port = 8080
local ok, err = balancer.set_current_peer(host, port)
if not ok then
ngx.log(ngx.ERR, "failed to set the current peer: ", err)
return ngx.exit(500)
end
}
}
keepalive 10; # connection pool
};
server {
init_worker_by_lua_block {
local hc = require "resty.upstream.healthcheck"
local ok, err = hc.spawn_checker{
shm = "healthchecks", -- defined by "lua_shared_dict"
upstream = "YOURAPP", -- defined by "upstream"
type = "http",
-- get /healthcheck with a host header
http_req = "GET /healthcheck HTTP/1.0\r\nHost: some.host.header.if.needed.com\r\n\r\n",
interval = 2000, -- run the check cycle every 2 sec
timeout = 1000, -- 1 sec is the timeout for network operations
fall = 3, -- # of successive failures before turning a peer down
rise = 2, -- # of successive successes before turning a peer up
-- Adding 301 as an acceptable response code in case the route changes somehow
valid_statuses = {200}, -- a list valid HTTP status code (indicating a healthy upstream)
concurrency = 10, -- concurrency level for test requests
}
if not ok then
ngx.log(ngx.ERR, "failed to spawn health checker: ", err)
return
end
}
location /healthcheck {
default_type application/json;
# Determine if the upstream is healthy by having atleast 1 healthy server
content_by_lua_block {
local cjson = require("cjson")
-- Pcall to avoid barfing on old versions of resty
local ok, upstream = pcall(require, "ngx.upstream")
if not ok then
ngx.status = ngx.HTTP_INTERNAL_SERVER_ERROR
ngx.log(ngx.ERR, "ngx_upstream_lua module required")
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
return
end
-- This is gonna ugly
-- Time is short.. do better
local ret = { Status = "DOWN", Data = {} }
local us, err = upstream.get_upstreams()
if not us then
ngx.status = ngx.HTTP_INTERNAL_SERVER_ERROR
ngx.say(ret)
ngx.log(ngx.ERR, "failed to get upstream names: " .. err)
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
return
end
local n = #us
local found = false
local down = false
for i = 1, n do
local u = us[i]
if u == "YOURAPP" then
found = true
local peers, err = upstream.get_primary_peers(u)
if not peers then
ret.Error = "failed to get primary peers in upstream " .. u .. ": " .. err
ngx.status = ngx.HTTP_INTERNAL_SERVER_ERROR
ngx.say(cjson.encode(ret))
ngx.log(ngx.ERR, "failed to get primary peers in upstream " .. u .. ": " .. err)
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
return
end
ret.Data = peers
-- Terminate upstream loop
break
end
end
if #ret.Data == 0 then
ngx.status = ngx.HTTP_INTERNAL_SERVER_ERROR
ngx.say(cjson.encode(ret))
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
return
end
if ret.Data[1].down then
ngx.status = ngx.HTTP_INTERNAL_SERVER_ERROR
ngx.say(cjson.encode(ret))
ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
return
else
ret.Status = "UP"
ret.Data[1].down = false
ngx.status = ngx.HTTP_OK
ngx.say(cjson.encode(ret))
ngx.exit(ngx.HTTP_OK)
return
end
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment