openresty / openresty/lua-nginx-module
ngx.location.capture_multi and proxy_pass upstream issue
Nobody has claimed this yet.
- Dominant language
- C
- Stars
- 11.8k
- Forks
- 2.1k
- Avg merge
- 6h 1m
- Merged PRs (30d)
- 6
Description
This is my nginx.conf:
upstream backend_services {
server $servicediscovery;
keepalive 512;
}
lua_shared_dict token_cache 100M;
lua_shared_dict prometheus_metrics 10M;
lua_package_path '/etc/nginx/conf.d/lua/?.lua;;';
init_by_lua_block {
prometheus = require("prometheus").init("prometheus_metrics")
metric_requests = prometheus:counter(
"http_requests_total", "Number of HTTP requests", {"host", "status"})
metric_latency = prometheus:histogram(
"http_request_duration_seconds", "HTTP request latency", {"host", "method", "uri", "status"}, {0.3})
metric_connections = prometheus:gauge(
"http_connections", "Number of HTTP connections", {"state"})
}
log_by_lua_block {
metric_requests:inc(1, {ngx.var.host, ngx.var.status})
local news_pattern = "/news/blog/index.php"
local pattern = "/(%w+)/(%w+)/(%w+)"
local begin, last = string.find(ngx.var.uri, pattern)
local n_begin, n_last = string.find(ngx.var.uri, news_pattern)
local log_uri = nil
if begin == nil then
log_uri = ngx.var.uri
else
if n_begin ~= nil then
log_uri = string.gsub(ngx.var.uri,"/$","")
else
log_uri = string.sub(ngx.var.uri, begin, last)
end
end
metric_latency:observe(ngx.now() - ngx.req.start_time(), {ngx.var.host,ngx.var.request_method,log_uri,ngx.var.status})
}
server {
gzip on;
gzip_types text/plain application/xml application/json;
gzip_min_length 1000;
listen 8080;
location /ccg/prometheus/metrics {
content_by_lua_block {
metric_connections:set(ngx.var.connections_active, {"active"})
metric_connections:set(ngx.var.connections_reading, {"reading"})
metric_connections:set(ngx.var.connections_waiting, {"waiting"})
metric_connections:set(ngx.var.connections_writing, {"writing"})
prometheus:collect()
}
}
location /ccg/healthcheck {
#default_type application/json;
add_header User-Agent $http_user_agent;
return 200 'HTTP Status 200';
}
location /ccg/authorize {
# "http://MESH_PROXY_SERVICE/clspl/clinical"
rewrite /ccg/(.*) /$clsservicediscovery/clinical/$1 break;
proxy_pass http://backend_services;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
}
location /ccg/blog {
# "http://MESH_PROXY_SERVICE/news/blog"
access_by_lua_file /etc/nginx/conf.d/lua/auth.lua;
rewrite /ccg/(.*) /$newsservicediscovery/$1 break;
proxy_pass http://backend_services;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
}
location /ccg/formularyservice {
content_by_lua_file /etc/nginx/conf.d/lua/auth_with_upstream.lua;
}
location /forward/ccg/formularyservice {
#"http://MESH_PROXY_SERVICE/formulary/formularyservice";
rewrite /forward/ccg/(.*) /$formularyservicediscovery/$1 break;
proxy_pass http://backend_services;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
}
location /ccg/cts {
content_by_lua_file /etc/nginx/conf.d/lua/auth_with_upstream.lua;
}
location /forward/ccg/cts {
#"http://<s2s url>//cts"
#access_by_lua_file /etc/nginx/conf.d/lua/auth.lua;
rewrite /forward/ccg/(.*) /$1 break;
proxy_pass http://$SEARCH_SERVICE_BASE_URL;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
location /ccg/term {
content_by_lua_file /etc/nginx/conf.d/lua/auth_with_upstream.lua;
}
location /forward/ccg/term {
#"http://MESH_PROXY_SERVICE/termservice/term"
rewrite /forward/ccg/(.*) /$termservicediscovery/$1 break;
proxy_pass http://backend_services;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
}
location /verifytoken/mtws.do {
rewrite /verifytoken/(.*) /$ecomservicediscovery/$1 break;
proxy_pass http://backend_services;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
}
}
where SEARCH_SERVICE_BASE_URL = search-s2s.us-west-2.dev.epocrates.aws.athenahealth.com
and my auth_with_upstream.lua is
local expiry_time_secs = 86400 -- expiry time for entries in token cache
local token_cache = ngx.shared.token_cache
local value, flags = token_cache:get(epltokenescaped) -- Always try reading token from cache
if value == nil or value == '' or crdescaped == nil or crdescaped == '' or value ~= crdescaped then
ngx.log(ngx.DEBUG, "Inside if block of lua file")
local requestUri = '/forward' .. ngx.var.request_uri
ngx.log(ngx.DEBUG, "Request URI : " .. requestUri)
local auth_res, upstream_res = ngx.location.capture_multi ({
{'/verifytoken/mtws.do?', { args = { crd = crdescaped, epltoken = epltokenescaped, mode = 'liteAuth' } } },
{ '/forward' .. ngx.var.request_uri, { method = request_method_supported[ngx.var.request_method], body = ngx.var.request_body} },
})
local auth_response = auth_res.body
local json_response = cjson.decode(auth_response)
local userId = json_response.userId
local upstream_response = upstream_res.body
ngx.log(ngx.DEBUG, "Response Body : " .. upstream_res.body)
ngx.log(ngx.DEBUG, "Response Status : " .. upstream_res.status)
local unAuthorizedJsonResponse = cjson.encode({
version = "1",
userId = 0,
token = "TBD"
})
if auth_res.status == ngx.HTTP_OK and userId > 0 then
token_cache:set(epltokenescaped, crdescaped, expiry_time_secs)
if upstream_res.status == ngx.HTTP_OK then
ngx.status = upstream_res.status
for header_name, header in pairs(upstream_res.header) do
ngx.header[header_name] = header
end
ngx.print(upstream_res.body)
ngx.flush(true)
end
ngx.exit(upstream_res.status)
else
ngx.status = ngx.HTTP_UNAUTHORIZED
ngx.header.content_type = 'application/json'
auth_res.body = unAuthorizedJsonResponse
ngx.print(auth_res.body)
ngx.exit(ngx.status)
end
else
ngx.log(ngx.DEBUG, "Inside else block of lua file")
local requestUri = '/forward' .. ngx.var.request_uri
ngx.log(ngx.DEBUG, "Request URI : " .. requestUri)
local upstream_res = ngx.location.capture('/forward' .. ngx.var.request_uri, { method request_method_supported[ngx.var.request_method], body = ngx.var.request_body})
local response = upstream_res.body
ngx.log(ngx.DEBUG, "Response Body : " .. upstream_res.body)
ngx.log(ngx.DEBUG, "Response Status : " .. upstream_res.status)
if upstream_res.status == ngx.HTTP_OK then
ngx.status = upstream_res.status
for header_name, header in pairs(upstream_res.header) do
ngx.header[header_name] = header
end
ngx.print(response)
ngx.flush(true)
end
ngx.exit(upstream_res.status)
end
Any request of the form /ccg/cts , first go to auth_with_upstream.lua and tries to initiate two paraller request . One is for authentication /verifytoken/mtws.do? and other is for the upstream /forward/ccg/cts .
Inside nginx.conf in location directive of /forward/ccg/cts , proxy_pass is defined as mentioned above. Very strange issue I am facing. Sometimes the request to /ccg/cts succeeds and sometime it fails with 502 gateway error. If I restart this nginx service , then again the issue is resolved but after sometime again it starts.
NOTE : All my services are deployed in EC2 of AWS.
This is my logs :
`[debug] 26#26: *1495 [lua] auth_with_upstream.lua:26: Inside if block of lua file
[debug] 26#26: *1495 [lua] auth_with_upstream.lua:28: Request URI : /forward/ccg/cts/search?kgFlags=feature_kg_related_dx,feature_kg_rx_class,feature_kg_rx_for&appVersion=23.2.0-dev%20debug&os=Android&query=hydroxyzine&start=0&userId=9818732&token=df8093c4286c9306e053da54870a8ae3&core=all18_6&osVersion=12&end=30&premUser=true&qp=1&username=test_medinfo_p@epocrates.com.tttt
2023/02/14 15:58:14 [notice] 26#26: 1495 "/verifytoken/(.)" matches "/verifytoken/mtws.do", client: 10.135.114.41, server: , request: "GET /ccg/cts/search?kgFlags=feature_kg_related_dx,feature_kg_rx_class,feature_kg_rx_for&appVersion=23.2.0-dev%20debug&os=Android&query=hydroxyzine&start=0&userId=9818732&token=df8093c4286c9306e053da54870a8ae3&core=all18_6&osVersion=12&end=30&premUser=true&qp=1&username=test_medinfo_p@epocrates.com.tttt HTTP/1.1", subrequest: "/verifytoken/mtws.do", host: "content.dev.epocrates.com"
[notice] 26#26: *1495 rewritten data: "/ecm/mtws.do", args: "crd=test_medinfo_p%40epocrates.com.tttt&epltoken=df8093c4286c9306e053da54870a8ae3&mode=liteAuth", client: 10.135.114.41, server: , request: "GET /ccg/cts/search?kgFlags=feature_kg_related_dx,feature_kg_rx_class,feature_kg_rx_for&appVersion=23.2.0-dev%20debug&os=Android&query=hydroxyzine&start=0&userId=9818732&token=df8093c4286c9306e053da54870a8ae3&core=all18_6&osVersion=12&end=30&premUser=true&qp=1&username=test_medinfo_p@epocrates.com.tttt HTTP/1.1", subrequest: "/verifytoken/mtws.do", host: "content.dev.epocrates.com"
[notice] 26#26: 1495 "/forward/ccg/(.)" matches "/forward/ccg/cts/search", client: 10.135.114.41, server: , request: "GET /ccg/cts/search?kgFlags=feature_kg_related_dx,feature_kg_rx_class,feature_kg_rx_for&appVersion=23.2.0-dev%20debug&os=Android&query=hydroxyzine&start=0&userId=9818732&token=df8093c4286c9306e053da54870a8ae3&core=all18_6&osVersion=12&end=30&premUser=true&qp=1&username=test_medinfo_p@epocrates.com.tttt HTTP/1.1", subrequest: "/forward/ccg/cts/search", host: "content.dev.epocrates.com"
[notice] 26#26: *1495 rewritten data: "/cts/search", args: "kgFlags=feature_kg_related_dx,feature_kg_rx_class,feature_kg_rx_for&appVersion=23.2.0-dev%20debug&os=Android&query=hydroxyzine&start=0&userId=9818732&token=df8093c4286c9306e053da54870a8ae3&core=all18_6&osVersion=12&end=30&premUser=true&qp=1&username=test_medinfo_p@epocrates.com.tttt", client: 10.135.114.41, server: , request: "GET /ccg/cts/search?kgFlags=feature_kg_related_dx,feature_kg_rx_class,feature_kg_rx_for&appVersion=23.2.0-dev%20debug&os=Android&query=hydroxyzine&start=0&userId=9818732&token=df8093c4286c9306e053da54870a8ae3&core=all18_6&osVersion=12&end=30&premUser=true&qp=1&username=test_medinfo_p@epocrates.com.tttt HTTP/1.1", subrequest: "/forward/ccg/cts/search", host: "content.dev.epocrates.com"
[error] 26#26: *1495 connect() failed (113: No route to host) while connecting to upstream, client: 10.135.114.41, server: , request: "GET /ccg/cts/search?kgFlags=feature_kg_related_dx,feature_kg_rx_class,feature_kg_rx_for&appVersion=23.2.0-dev%20debug&os=Android&query=hydroxyzine&start=0&userId=9818732&token=df8093c4286c9306e053da54870a8ae3&core=all18_6&osVersion=12&end=30&premUser=true&qp=1&username=test_medinfo_p@epocrates.com.tttt HTTP/1.1", subrequest: "/cts/search", upstream: "http://10.135.116.127:80/cts/search?kgFlags=feature_kg_related_dx,feature_kg_rx_class,feature_kg_rx_for&appVersion=23.2.0-dev%20debug&os=Android&query=hydroxyzine&start=0&userId=9818732&token=df8093c4286c9306e053da54870a8ae3&core=all18_6&osVersion=12&end=30&premUser=true&qp=1&username=test_medinfo_p@epocrates.com.tttt", host: "content.dev.epocrates.com"
[warn] 26#26: *1495 upstream server temporarily disabled while connecting to upstream, client: 10.135.114.41, server: , request: "GET /ccg/cts/search?kgFlags=feature_kg_related_dx,feature_kg_rx_class,feature_kg_rx_for&appVersion=23.2.0-dev%20debug&os=Android&query=hydroxyzine&start=0&userId=9818732&token=df8093c4286c9306e053da54870a8ae3&core=all18_6&osVersion=12&end=30&premUser=true&qp=1&username=test_medinfo_p@epocrates.com.tttt HTTP/1.1", subrequest: "/cts/search", upstream: "http://10.135.116.127:80/cts/search?kgFlags=feature_kg_related_dx,feature_kg_rx_class,feature_kg_rx_for&appVersion=23.2.0-dev%20debug&os=Android&query=hydroxyzine&start=0&userId=9818732&token=df8093c4286c9306e053da54870a8ae3&core=all18_6&osVersion=12&end=30&premUser=true&qp=1&username=test_medinfo_p@epocrates.com.tttt", host: "content.dev.epocrates.com"`
If you notice in the logs , the upstream call is going as http://10.135.116.127:80/cts/search?kgFlags=feature_kg_related_dx...
but actually it should be as http://search-s2s.us-west-2.dev.epocrates.aws.athenahealth.com/cts/search?kgFlags=feature_kg_related_dx....
Please help me resolve this issue. I tried adding resolver inside location directive suspecting it could be issue because of elastic IP in aws but that did not help. Not sure what is the root cause.
PS : Other services working fine which are using backend_services as upstream.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with auth_with_upstream.lua and the /forward/ccg/cts location in nginx.conf, focusing on the ngx.location.capture_multi calls and the logged 502 response. Compare successful and failing requests using the debug log, especially the “No route to host” message for 10.135.116.127:80. Done means identifying the cause of the intermittent upstream failure and documenting a reproducible fix or configuration change.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- lua, nginx
- Domain
- backend, networking
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100