openresty / lua-resty-mysql

Nonblocking Lua MySQL driver library for ngx_lua or OpenResty
708 stars 236 forks source link

Blocking mode? #77

Closed SvenAlHamad closed 6 years ago

SvenAlHamad commented 6 years ago

Hi,

I'm trying to create a reverse proxy, where the upstream location is defined inside a mysql table. I'm using this module to fetch the target, however I'm having a problem since this module works in a non-blocking mode.

Imagine this code:

set $target "";
access_by_lua_file /etc/openresty/scripts/code-to-set-target.lua;
proxy_pass https://$target;

$target is always empty when executing the proxy_pass line, but actually the problem is that the variable inside the lua scripts is populated only when the mysql result is returned, which can happen after the proxy_pass line is executed.

My question is, how can I force the mysql module to wait until results are returned, before proceeding with the rest of the execution?

agentzh commented 6 years ago

@SvenAlHamad Nonblocking means not blocking any OS threads. This library's API is nonblocking but synchronous, meaning that the current request will not continue without waiting for the MySQL replies.

SvenAlHamad commented 6 years ago

Hmm...but in that case I'm not sure why my code doesn't work:

code-to-set-target.lua;

local mysql = require "resty.mysql"
local db, err = mysql:new()
if not db then
    ngx.say("failed to instantiate mysql: ", err)
    return
end

db:set_timeout(1000) -- 1 sec

local ok, err, errcode, sqlstate = db:connect{
    host = "----",
    port = 3306,
    database = "proxy",
    user = "----",
    password = "-----",
    charset = "utf8",
    max_packet_size = 1024 * 1024,
}

if not ok then
    ngx.say("failed to connect: ", err, ": ", errcode, " ", sqlstate)
    return
end

--ngx.say("connected to mysql.")

local quoted_name = ngx.quote_sql_str(ngx.var.host)
res, err, errcode, sqlstate = db:query("select target from domains where domain = " .. quoted_name, 1)

if not res then
    ngx.say("bad result: ", err, ": ", errcode, ": ", sqlstate, ".")
    return
end

local cjson = require "cjson"
--ngx.say("result: ", cjson.encode(res))
local temp = res[1].target
--ngx.say("temp: ", temp)
ngx.var.target = temp
--ngx.say("ngx var: ", ngx.var.target)

local ok, err = db:set_keepalive(10000, 100)

if not ok then
    ngx.say("failed to set keepalive: ", err)
    return
end

When I uncomment the ngx.say calls, I get an output with the correct values.

But then inside my nginx.conf file, the proxy pass $target value seems to be empty. In case I manually set a hardcoded value for ngx.var.target inside the lua script, that value is passed correctly to the nginx.conf. That's why I thought it's got something to do with the non-blocking nature.

This is the extract from the nginx.conf.

location / {
    set $target;
    rewrite_by_lua_file /etc/openresty/scripts/code-to-set-target.lua;

    # proxy
    proxy_pass https://$host$target;
}
agentzh commented 6 years ago

@SvenAlHamad You cannot use ngx.say() to generate a response in the rewrite phase otherwise your proxy_pass won't have a chance to generate its own response.

agentzh commented 6 years ago

@SvenAlHamad For debugging purposes, you should use ngx.log() or print() instead.

SvenAlHamad commented 6 years ago

@agentzh thanks for the tip!

I've used ngx.say just for testing. But even if replace all the instances of that call with print, I get exactly the same behavior as before. My variable is still not populated, but in the logs, I see the print entries with the correct values. However, I've then tried outputting the value of the $target like so, and I get back an empty response:

nginx.conf

location / {
    set $target;
    rewrite_by_lua_file /etc/openresty/scripts/code-to-set-target.lua;
    return 200 $target;
}

Have any ideas why that might be?

agentzh commented 6 years ago

@SvenAlHamad return directive runs before rewrite_by_lua_file no matter how you arrange them in nginx.conf. I suggest you read my tutorials first to be aware of such pitfalls:

https://openresty.org/download/agentzh-nginx-tutorials-en.html