1

I have a lua script with code block as below:

local call_data     = cjson.decode(ARGV[1])
local other_data    = cjson.decode(ARGV[2])
local data          = {}
local next          = next
local populate_data = function(source)
  if next(source) == nil then
    return
  end

  for property,value in pairs(source) do
    redis.call('HSET', KEYS[2], property, value)
  end
end
populate_data(call_data)
populate_data(other_data)

When I try to run the script with the following command KEYS and ARGV as:-

redis-cli --eval dialed.lua "inflight_stats:18" "calls:AC443d7a8111a96ba8074f54a71f0521ce:CA1ec49703eee1959471c71506f43bb42e:dialed" , "{\"from\":\"+18035224181\",\"to\":\"+919943413333\",\"sid\":\"CA1ec49703eee1959471c71506f43bb42e\",\"status\":\"queued\",\"direction\":\"outbound-api\",\"date_created\":null,\"account_sid\":\"AC443d8a8111a96ba8074f54a71f0521ce\"}" "{\"phone\":\"919943413333\",\"campaign_id\":18,\"caller_session_sid\":\"CA828b163153bf5cc301ef5285e38925f9\"}" 0

Error :-

(error) ERR Error running script (call to f_08dcc69ee8baa0200e0cf552948ab4bc338c9978): @user_script:11: @user_script: 11: Lua redis() command arguments must be strings or integers 
Itamar Haber
  • 47,336
  • 7
  • 91
  • 117
Jaswinder
  • 1,455
  • 14
  • 27
  • Υou can use: ./redis-cli --ldb --eval /tmp/script.lua mykey somekey , arg1 arg2 – georgeliatsos Oct 19 '18 at 09:10
  • @gliatsos please check the above description for once. I am already doing it with the same for testing – Jaswinder Oct 19 '18 at 10:32
  • Running this script returns (nil). As you're not calling `populate_data`, I can't see how you get to line 11. – Itamar Haber Oct 19 '18 at 12:20
  • @ItamarHaber yes I haven't mentioned calling reference to pupulate_data due to some private concerns but yes it has been called. I think it is something related to lightuserdata for 'value' getting 'light-userdata@(nil)' but not sure how to identify this 'value' equals nil – Jaswinder Oct 19 '18 at 12:28
  • @ItamarHaber you have a great experience with Lua scripts and I really appreciate if you could help me out of this. – Jaswinder Oct 19 '18 at 12:52

1 Answers1

3

TL;DR for values returned by cjson.decode(), use cjson.null to compare to JSON's null value.

Explanation: Lua uses nil in tables to mark deleted entries. If JSONinc nulls were converted to Lunatic nils, the decoded objects would be corrupt. Therefore, the cjson lib uses a lightweight userdata type to represent null/nil.

Your 'call_data' has a 'date_created' field that is null - that causes the error.

The funny thing is that Redis, like Lua, will not store a nil/null value, so you'll have to either ignore null values or use a special value in Redis to flag them.

Assuming you'll be ignoring them, here's one way around it:

local call_data     = cjson.decode(ARGV[1])
local other_data    = cjson.decode(ARGV[2])
local data          = {}
local next          = next
local null          = cjson.null
local populate_data = function(source)
  if next(source) == nil then
    return
  end

  for property,value in pairs(source) do
    if value ~= null then
      redis.call('HSET', KEYS[2], property, value)
    end
  end
end
populate_data(call_data)
populate_data(other_data)

Also, a small optimization would be to batch the updates, like so:

  local payload = {}
  for property,value in pairs(source) do
    if value ~= null then
      table.insert(payload, property)
      table.insert(payload, value)
    end
  end
  redis.call('HSET', KEYS[2], unpack(payload))

P.S. if you want, look at ReJSON that I wrote - it is designed to help with what it appears that you're trying to do.

Itamar Haber
  • 47,336
  • 7
  • 91
  • 117