openresty / lua-nginx-module

Embed the Power of Lua into NGINX HTTP servers

Home Page:https://openresty.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

API disabled in the context of set_by_lua*

StemonZhang opened this issue · comments

Lua is like the bridge between Nginx and Server.
I wanted to get data from MySQL , then redirect the request based on the data.
So I use the set_by_lua API.
Like this:

    location /hello {
    set_by_lua $res '
       local mysql = require "resty.mysql"
       local db, err = mysql:new()
       if not db then
          ngx.say("failed ti instantiate mysql: ", err)
           return
       end

       db:set_timeout(1000)

       local ok, err, errno, sqlstate = db:connect{
            host = "",
            port = 3306,
            database = "",
            user = "",
            password = ""
       }
       if not ok then
            ngx.say("failed to connect: ", err, ": ", errno, " ", sqlstate) ;
            return
      end

      ngx.say("connected to mysql.")

      res, err, errno, sqlstate = db:query("select XXX from YYY order by ZZZ desc limit 1")

      if not res then
         ngx.say("bad result: ", err, ":", errno, ":", sqlstate, ".")
         return  
      end
      '; }

But when I access the IP address, it's failed.
I checked the error.log, it said that:

failed to run set_by_lua_: /usr/local/lib/lua/resty/mysql.lua:449: API disabled in the context of set_by_lua_
stack traceback:
[C]: in function 'tcp'
/usr/local/lib/lua/resty/mysql.lua:449: in function 'new'
[string "set_by_lua"]:3: in function <[string "set_by_lua"]:1>, client:, server: , request: "GET /hello HTTP/1.1", host: ""

It's a big surprise!

Then I checked the specification:

set_by_lua
syntax: set_by_lua $res [$arg1 $arg2 ...]
context: server, server if, location, location if
phase: server-rewrite, rewrite

Also the example:

    location /foo {
    set $diff ''; # we have to predefine the $diff variable here
    set_by_lua $sum '
        local a = 32
        local b = 56

        ngx.var.diff = a - b;  -- write to $diff directly
        return a + b;          -- return the $sum value normally
    ';
    echo "sum = $sum, diff = $diff";
}

What's wrong with my Nginx?
There is a lot of things I shoud to learn~
Thx~

@StemonZhang lua-resty-mysql relies on ngx_lua's cosocket API which is not available in the set_by_lua* context due to the underlying limitations in nginx's standard ngx_rewrite module (you cannot do nonblocking I/O in ngx_rewrite module's directives).

This limitation is already documented in lua-resty-mysql's README: https://github.com/agentzh/lua-resty-mysql#limitations To quote, "this library cannot be used in code contexts like init_by_lua_, set_by_lua_, log_by_lua_, and header_filter_by_lua_ where the ngx_lua cosocket API is not available."

You can work around this limitation by using rewrite_by_lua or access_by_lua instead, in which you can access all the ngx_lua's Lua API including the cosocket API and nginx variable API.

Regards,
-agentzh

I got it~
Thank you very much,Big Zhang^_^

At 2013-08-27 06:38:40,"Yichun Zhang" notifications@github.com wrote:

@StemonZhang lua-resty-mysql relies on ngx_lua's cosocket API which is not available in the set_by_lua* context due to the underlying limitations in nginx's standard ngx_rewrite module (you cannot do nonblocking I/O in ngx_rewrite module's directives).

This limitation is already documented in lua-resty-mysql's README: https://github.com/agentzh/lua-resty-mysql#limitations To quote, "this library cannot be used in code contexts like init_by_lua_, set_by_lua_, log_by_lua_, and header_filter_by_lua_ where the ngx_lua cosocket API is not available."

You can work around this limitation by using rewrite_by_lua or access_by_lua instead, in which you can access all the ngx_lua's Lua API including the cosocket API and nginx variable API.

Regards,
-agentzh


Reply to this email directly or view it on GitHub.

Consider it resolved.

@agentzh , so basically, if i want for example to enrich Headers that are stored somewhere else, i can't do that ?

@driverpt Why are you sticking with set_by_lua*? There are many other alternatives like rewrite_by_lua* which have little limitations.

@driverpt Actually I've already suggested solutions in my earlier comments:

You can work around this limitation by using rewrite_by_lua or access_by_lua instead, in which you can access all the ngx_lua's Lua API including the cosocket API and nginx variable API.

I'm using Kong.

problem:API disabled in the context of set_by_lua*?

error code:

lua-resty-redis/lib/resty/redis.lua:59: API disabled in the context of set_by_lua*
stack traceback:

Solution ideas @agentzh

You can work around this limitation by using rewrite_by_lua or access_by_lua instead, in which you can access all the ngx_lua's Lua API including the cosocket API and nginx variable API.

Solution:

I can work around this limitation by using rewrite_by_lua_file

nginx.conf

      location ~ /hls/(\d+).m3u8$ {
                set $a $1;  # eg : 123456789
                set $stream_id "";  # we have to predefine the $stream_id variable here
                default_type 'text/html';
                lua_code_cache off;
                rewrite_by_lua_file  /home/www/lua-tinywan/set_by_file.lua;
                echo "stream_id :" $stream_id;
        }

set_by_file.lua

local stream_a = ngx.var.a
local redis = require("resty.redis");
local redis_instance = redis:new();
redis_instance:set_timeout(1000)
local ip = '127.0.0.1'
local port = 6379
local ok,err = redis_instance:connect(ip,port)
if not ok then
        ngx.say("connect redis error : ",err)
        return err
end

local resp, err = redis_instance:hget("liveNodeRedis:"..stream_a,'liveNode')
if not resp then
    ngx.say("get msg error : ", err)
    return err
end

if resp == ngx.null then
    ngx.say("this is not redis_data") 
    return nil
end

ngx.var.stream_id = resp

redis date

127.0.0.1:6379> HMSET liveNodeRedis:123456789 stream_id 123456789 liveNode "https://github.com/Tinywan/hls/123456789.m3u8" time 18:11
OK
127.0.0.1:6379> keys *
1) "liveNodeRedis:123456789"
127.0.0.1:6379> hget liveNodeRedis:123456789 liveNode
"https://github.com/Tinywan/hls/123456789.m3u8"
127.0.0.1:6379>

curl test

root@iZ236j3sofdZ:/usr/local/nginx/conf/lua# curl "http://localhost/hls/123456789.m3u8"
stream_id : https://github.com/Tinywan/hls/123456789.m3u8