-
Notifications
You must be signed in to change notification settings - Fork 33
/
hipache-nginx.cfg
102 lines (91 loc) · 2.8 KB
/
hipache-nginx.cfg
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
set $backend '';
set $backends_len '';
set $backend_id '';
set $frontend '';
set $vhost '';
access_by_lua '
-- Connect to Redis
local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000)
local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
ngx.say("Failed to connect to Redis: ", err)
return
end
-- Extract only the hostname without the port
local frontend = ngx.re.match(ngx.var.http_host, "^([^:]*)")[1]
-- Extract the domain name without the subdomain
local domain_name = ngx.re.match(frontend, "(\.[^.]+\.[^.]+)$")[1]
-- Redis lookup
red:multi()
red:lrange("frontend:" .. frontend, 0, -1)
red:lrange("frontend:*" .. domain_name, 0, -1)
red:smembers("dead:" .. frontend)
local ans, err = red:exec()
if not ans then
ngx.say("Lookup failed: ", err)
return
end
-- Parse the result of the Redis lookup
local backends = ans[1]
if #backends == 0 then
backends = ans[2]
end
if #backends == 0 then
ngx.say("Backend not found")
return
end
local vhost_name = backends[1]
table.remove(backends, 1)
local deads = ans[3]
-- Pickup a random backend (after removing the dead ones)
local indexes = {}
for i, v in ipairs(deads) do
deads[v] = true
end
for i, v in ipairs(backends) do
if deads[tostring(i)] == nil then
table.insert(indexes, i)
end
end
local index = indexes[math.random(1, #indexes)]
local backend = backends[index]
-- Announce dead backends if there is any
local deads = ngx.shared.deads
for i, v in ipairs(deads:get_keys()) do
red:publish("dead", deads:get(v))
deads:delete(v)
end
-- Set the connection pool (to avoid connect/close everytime)
red:set_keepalive(0, 100)
-- Export variables
ngx.var.backend = backend
ngx.var.backends_len = #backends
ngx.var.backend_id = index - 1
ngx.var.frontend = frontend
ngx.var.vhost = vhost_name
';
if ($http_x_debug) {
add_header X-Debug-Backend-Url $backend;
add_header X-Debug-Backend-Id $backend_id;
add_header X-Debug-Vhost $vhost;
add_header X-Debug-Frontend-Key $frontend;
}
proxy_pass $backend;
header_filter_by_lua '
local code = ngx.status
-- Mark the backend as dead only for 5xx errors
if not (ngx.status >= 501 and ngx.status ~= 503) then
return
end
local frontend = ngx.var.frontend
if #frontend == 0 then
return
end
-- Put the dead backends in a shared dict (we cannot call Redis from here)
local deads = ngx.shared.deads
local line = frontend .. ";" .. ngx.var.backend .. ";" ..
ngx.var.backend_id .. ";" .. ngx.var.backends_len
deads:set(ngx.var.frontend .. ngx.var.backend_id, line)
';