Giter Site home page Giter Site logo

lua-resty-redis-cluster's Issues

attempt to index a nil value

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/

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.