Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

attempt to index a nil value #4

Open
nandreev87 opened this issue Dec 5, 2019 · 0 comments
Open

attempt to index a nil value #4

nandreev87 opened this issue Dec 5, 2019 · 0 comments

Comments

@nandreev87
Copy link

I'm trying fetch data from redis cluster via openresty nginx + LuaJIT + this module.
I've tried different enviroment (alpine-fat \ stretch \ with and without LuaRocks \ openresty 1.13 - 1.15) and got same error.
Probably trouble with resty.utils, but same config work perfectly at one of physical servers...

Error message:
lua entry thread aborted: runtime error: /usr/local/openresty/lualib/rediscluster.lua:296: attempt to index a nil value
stack traceback:
/usr/local/openresty/lualib/rediscluster.lua:416: in function 'smembers'
/lua/read.lua:34: in function 'r_members'
/lua/read.lua:70: in function 'gatherNightNodes'
/lua/read.lua:208: in function 'dispatcher'

My last setup:

  1. openresty + opm
    xiedacon/lua-pretty-json 0.1
    fffonion/lua-resty-shdict-server 0.02
    xiangnanscu/lua-resty-utils 1.21
    openresty/lua-resty-redis 0.25
    xiangnanscu/lua-resty-repr 1.0
    openresty/lua-resty-lock 0.07

openresty -V
nginx version: openresty/1.15.8.2
built by gcc 8.3.0 (Alpine 8.3.0)
built with OpenSSL 1.1.1c 28 May 2019
TLS SNI support enabled
configure arguments: --prefix=/usr/local/openresty/nginx --with-cc-opt='-O2 -DNGX_LUA_ABORT_AT_PANIC -I/usr/local/openresty/pcre/include -I/usr/local/openresty/openssl/include' --add-module=../ngx_devel_kit-0.3.1rc1 --add-module=../echo-nginx-module-0.61 --add-module=../xss-nginx-module-0.06 --add-module=../ngx_coolkit-0.2 --add-module=../set-misc-nginx-module-0.32 --add-module=../form-input-nginx-module-0.12 --add-module=../encrypted-session-nginx-module-0.08 --add-module=../srcache-nginx-module-0.31 --add-module=../ngx_lua-0.10.15 --add-module=../ngx_lua_upstream-0.07 --add-module=../headers-more-nginx-module-0.33 --add-module=../array-var-nginx-module-0.05 --add-module=../memc-nginx-module-0.19 --add-module=../redis2-nginx-module-0.15 --add-module=../redis-nginx-module-0.3.7 --add-module=../rds-json-nginx-module-0.15 --add-module=../rds-csv-nginx-module-0.09 --add-module=../ngx_stream_lua-0.0.7 --with-ld-opt='-Wl,-rpath,/usr/local/openresty/luajit/lib -L/usr/local/openresty/pcre/lib -L/usr/local/openresty/openssl/lib -Wl,-rpath,/usr/local/openresty/pcre/lib:/usr/local/openresty/openssl/lib' --with-pcre --with-compat --with-file-aio --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-http_xslt_module=dynamic --with-ipv6 --with-mail --with-mail_ssl_module --with-md5-asm --with-pcre-jit --with-sha1-asm --with-stream --with-stream_ssl_module --with-threads --with-stream --with-stream_ssl_preread_module
2) nginx.conf
worker_processes 20;
events {
worker_connections 4096;
multi_accept on;
use epoll;
}
http {
lua_shared_dict redis_cluster_slot_locks 100k;
log_format travelata '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" $request_time';
server {
listen 80;
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.0;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
proxy_set_header Accept-Encoding 'gzip';
access_log /dev/stdout;
error_log /dev/stdout;
location /searchOneThread {
default_type text/html;
content_by_lua_file "/lua/read.lua";
}
location /writeOneThread {
default_type text/html;
content_by_lua_file "/lua/write.lua";
}
location /nginx_status {
stub_status on;
access_log off;
}
}
}
3) content_by_lua_file "/lua/read.lua
local json = require('cjson')
local redis_cluster = require "rediscluster"
local utils = require "resty.utils"

ngx.req.read_body()

local data = ngx.req.get_body_data();
local request = json.decode(data);

local config = {
name = "testCluster", --rediscluster name
serv_list = { --redis cluster node list(host and port),
{ ip = "10.10.6.4", port = 6380 },
{ ip = "10.10.6.4", port = 6381 },
},
--enableSlaveRead = true,
keepalive_timeout = 60000, --redis connection pool idle timeout
keepalive_cons = 1000, --redis connection pool size
connection_timout = 1000, --timeout while connecting
max_redirection = 5, --maximum retry attempts for redirection
}

local red_c = redis_cluster:new(config)

local currentTime = os.time()

--[[
{"criteria":{"operators":[],"hotels":[],"resorts":[],"hotelCategories":[4,7,8,9],"nights":[7,8,9,10,11,12],"priceRangeFrom":6000,"priceRangeTo":1000000,"rootNodes":["20190308-92-2-2-0-0","20190309-92-2-2-0-0","20190310-92-2-2-0-0"],"meals":[],"limit":6000,"toursPerHotelLimit":8}}
]]--

local r_members = function (redis, key)

local res, err = redis:smembers(key)

if not res then
ngx.log("Error redis smembers key: " .. key .. "Error: " .. err)
end

return res
--[[
local co = coroutine.create(function (redis, key)
coroutine.yield(redis:smembers(key))
end)

return coroutine.resume(co, redis, key)
]]--
end

local hGetAll = function (redis, key, currentTime)
res, ok = redis:hgetall(key)

-- res, ok = redis:eval("local r = {} local t = {} for i, d in pairs(redis.call('HGETALL', KEYS[1])) do if(math.fmod(i,2) > 0) then t = {i = d, d = nil} else if tonumber(string.sub(d, 1,10)) > tonumber(ARGV[1]) then r[#r+1] = t.i r[#r+1] = d end t = {i = nil, d = nil} end end return r", 1, key, currentTime)

if not res then
return {}
end
return res;
-- return redis:array_to_hash(res)
end

local buildNodes = function (parentNodeKey, members)
local new = {}
for i,v in pairs(members) do new[i] = parentNodeKey .. "-" .. v end
return new
end;

local getNextLevelSmembers = function (redis, nodeType, nodeKey, criteria)
local members = r_members(redis, nodeType .. nodeKey);

if nodeType == "RootNode_" then
	if criteria.nights[1] == nil then
       return buildNodes(nodeKey, members)
    else
       return buildNodes(nodeKey, utils.filter(members, function(el) return utils.list_has(criteria.nights, tonumber(el)) end))
    end
elseif nodeType == "NightNode_" then
    if criteria.resorts[1] == nil then
       return buildNodes(nodeKey, members)
    else
       return buildNodes(nodeKey, utils.filter(members, function(el) return utils.list_has(criteria.resorts, tonumber(el)) end))
    end
elseif nodeType == "ResortNode_" then
    return members
end

end

local gatherNightNodes = function (redis, rootNode, criteria)
return getNextLevelSmembers(redis, "RootNode_", rootNode, criteria)
end

local gatherResortNodes = function (redis, nightNode, criteria)
return getNextLevelSmembers(redis, "NightNode_", nightNode, criteria)
end

local gatherPriceNodes = function (redis, resortNode, priceNodesCollection, criteria)

local priceBucketFrom = tonumber(criteria.priceRangeFrom) ~= nil and tonumber(criteria.priceRangeFrom) > 0 and math.floor(criteria.priceRangeFrom / 3000) or nil
local priceBucketTo = tonumber(criteria.priceRangeTo) ~= nil and tonumber(criteria.priceRangeTo) > 0 and math.floor(criteria.priceRangeTo / 3000) or nil

local priceNodes = getNextLevelSmembers(redis, "ResortNode_", resortNode, criteria)

for i,v in pairs(priceNodes) do
if (priceBucketFrom == nil or priceBucketFrom <= tonumber(v)) and (priceBucketTo == nil or priceBucketTo >= tonumber(v)) then
if priceNodesCollection[v] == nil then
priceNodesCollection[v] = {}
end
priceNodesCollection[v][#priceNodesCollection[v]+1] = resortNode .. "-" .. v
end
end

return priceNodesCollection
end

local gatherTours = function(redis, priceNodeCollection, criteria, currentTime)

local tours = {}
local count = 0
local nodeTours;

local needExit;
local cycle = 0;

local filteredTour = false
local totalFiltered = 0
local totalPriceNodesRead = 0

local tour = {
    identity = nil,
    data = {}
}

redis:init_pipeline()
for pool, priceNodePool in priceNodeCollection do
    for i, v in ipairs(priceNodePool) do
        totalPriceNodesRead = totalPriceNodesRead + 1
        redis:hgetall("PriceNode_" .. v)

-- ngx.say("PriceNode_" .. v)
end
end

local nodeBuckets = redis:commit_pipeline()
for i, nodeTours in pairs(nodeBuckets) do
    for key, val in pairs(nodeTours) do
	    local match = {}
	    if(math.fmod(key,2) > 0) then
	        tour = {
                identity = val,
                data = {}
            }
	    else
            for s in val:gmatch("([^;]*);?") do
                table.insert(tour.data, s)
            end


	        if tonumber(tour.data[1]) < currentTime then
		        filteredTour = true

-- totalFiltered = totalFiltered + 1
elseif tonumber(criteria.priceRangeFrom) ~= nill and tonumber(criteria.priceRangeTo) ~= nill and tonumber(criteria.priceRangeFrom) > 0 and tonumber(criteria.priceRangeTo) > tonumber(criteria.priceRangeFrom)
and (tonumber(criteria.priceRangeFrom) > tonumber(tour.data[4]) or tonumber(criteria.priceRangeTo) < tonumber(tour.data[4])) then
filteredTour = true
elseif criteria.operators[1] ~= nil and not utils.list_has(criteria.operators, tonumber(tour.data[6])) then
filteredTour = true
elseif criteria.hotels[1] ~= nil and not utils.list_has(criteria.hotels, tonumber(tour.data[3])) then
filteredTour = true
elseif criteria.hotelCategories[1] ~= nil and not utils.list_has(criteria.hotelCategories, tonumber(tour.data[18])) then
filteredTour = true
elseif criteria.meals[1] ~= nil and not utils.list_has(criteria.meals, tonumber(tour.data[17])) then
filteredTour = true
end

            if not filteredTour then
                tours[#tours+1] = tour
                count = count + 1
            else
                totalFiltered = totalFiltered + 1
            end

            tour = {
                identity = nil,
                data = {}
            }

            filteredTour = false
        end
    end
end

-- ngx.say("Total filtered: " .. totalFiltered)
-- ngx.say("Total price nodes read: " .. totalPriceNodesRead)
return tours

end

local dispatcher = function(utils, redis, criteria, currentTime)

 local allNightNodes = {}
 local allResortNodes = {}
 local allPriceNodes = {}
 local priceNodesCollection = {}

-- local sortedPriceNodes = {}

 for i,v in pairs(criteria.rootNodes) do
     allNightNodes = utils.list_extend(allNightNodes, gatherNightNodes(redis, v, criteria) or {})
 end

 for i,v in pairs(allNightNodes) do
     allResortNodes = utils.list_extend(allResortNodes, gatherResortNodes(redis, v, criteria) or {})
 end

--for i,v in pairs(allResortNodes) do
--ngx.say(v)
--end

 for i,v in pairs(allResortNodes) do
     priceNodesCollection = gatherPriceNodes(redis, v, priceNodesCollection, criteria)
 end


 local toursPerHotels = {}

 local tours = gatherTours(redis, utils.sorted(priceNodesCollection, function(a,b) return tonumber(a) < tonumber(b) end), criteria, currentTime)

 local sortedTours = {}

 for i,v in utils.sorted(tours, function(a,b)
    return
	tonumber(tours[a].data[4] or 0)
	+ tonumber((tours[a].data[7] and tours[a].data[7] ~= '') and tours[a].data[7] or 0)
	< tonumber(tours[b].data[4] or 0)
	+ tonumber((tours[b].data[7] and tours[b].data[7] ~= '') and tours[b].data[7] or 0)
	 end) do

if toursPerHotels[v.data[3]] == nil then
    toursPerHotels[v.data[3]] = 0
end

if toursPerHotels[v.data[3]] < criteria.toursPerHotelLimit then
        sortedTours[#sortedTours+1] = v
        toursPerHotels[v.data[3]] = toursPerHotels[v.data[3]] + 1
end

if(#sortedTours >= criteria.limit) then
   break
end

 end

return sortedTours

end

--local data, error = red_c:smembers("ResortNode_20190308-92-2-2-0-0-11-2162")

--local ok, members = r_members(red_c, "ResortNode_20190308-92-2-2-0-0-11-2162")

--local ok, members = r_members(red_c, "RootNode_" .. request.criteria.rootNodes[1]);

--local members = getNextLevelSmembers(red_c, "RootNode_", request.criteria.rootNodes[1])
--ngx.say(tonumber(request.criteria.priceRangeFrom))
local tours = dispatcher(utils, red_c, request.criteria, currentTime)
--res = red_c:eval("local r = {} local t = {} for i, d in pairs(redis.call('HGETALL', KEYS[1])) do if(math.fmod(i,2) > 0) then t = {i = d, d = nil} else if tonumber(string.sub(d, 1,10)) > tonumber(ARGV[1]) then r[#r+1] = t.i r[#r+1] = d end t = {i = nil, d = nil} end end return r", 1, "PriceNode_20190310-92-2-2-0-0-12-2185-25", currentTime)
--ngx.say(res[2])

red_c:close()
ngx.say(json.encode(tours))
--ngx.say("Total tours: " .. #tours)

--[[
--red_c:init_pipeline()
--red_c:hgetall("PriceNode_20190407-92-2-2-0-0-7-2161-8")
red_c:hgetall("PriceNode_20190407-92-2-2-0-0-8-2162-13")
red_c:hgetall("PriceNode_20190407-92-2-2-0-0-7-2184-13")
local res, err = red_c:commit_pipeline()
if not res then
ngx.log(ngx.ERR, "err: ", err)
else
ngx.say(json.encode(res))
end
--]]

--for i, v in pairs(members) do ngx.print(v .. "\n") end
4) redis_slot.so
gcc redis_slot.c -fPIC -shared -o redis_slot.so
cp redis_slot.so /usr/local/openresty/lualib/
cp rediscluster.lua /usr/local/openresty/lualib/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant