Describe the bug
A short description of the bug.
To reproduce
my code:
local function get_range_last(keys, args)
local key = args[1]
local start_time = args[2]
local end_time = args[3]
local result = redis.call('TS.REVRANGE', key, start_time, end_time, 'COUNT', 1, 'LATEST')
redis.log(redis.LOG_NOTICE, string.format("get_range_last for key %s: type of result is %s", key, type(result)))
redis.log(redis.LOG_NOTICE, string.format("get_range_last for key %s: #result is %s", key, #result))
if result and #result > 0 then
redis.log(redis.LOG_NOTICE, string.format("get_range_last for key %s: type of result[1] is %s", key, type(result[1])))
redis.log(redis.LOG_NOTICE, string.format("get_range_last for key %s: #result[1] is %s", key, #result[1]))
if type(result[1]) == "table" and #result[1] == 2 then
local timestamp = result[1][1]
local value = result[1][2]
redis.log(redis.LOG_NOTICE, string.format("get_range_last for key %s: timestamp = %s, value = %s", key, tostring(timestamp), tostring(value)))
return value
else
redis.log(redis.LOG_WARNING, string.format("get_range_last for key %s: Unexpected result structure", key))
return nil
end
else
return nil
end
end
redis log:
2024-07-10 13:57:26 8:M 10 Jul 2024 05:57:26.079 * get_range_last for key aaa:1m:open: type of result is table
2024-07-10 13:57:26 8:M 10 Jul 2024 05:57:26.079 * get_range_last for key aaa:1m:open: #result is 1
2024-07-10 13:57:26 8:M 10 Jul 2024 05:57:26.079 * get_range_last for key aaa:1m:open: type of result[1] is table
2024-07-10 13:57:26 8:M 10 Jul 2024 05:57:26.079 * get_range_last for key aaa:1m:open: #result[1] is 2
2024-07-10 13:57:26 8:M 10 Jul 2024 05:57:26.079 * get_range_last for key aaa:1m:open: timestamp = 1720574700, value = table: 0x563ee2039770
in redis-cli , it is 20 , not table
127.0.0.1:6379> TS.REVRANGE aaa:1m:volume - + COUNT 1 LASTEST
1) 1) (integer) 1720574700
2) 20
Comment From: sundb
@eromoe did you use RESP3? if so 20 should be {double: 20} in lua, you can print is by result[1][2]['double']
Comment From: eromoe
Now I use this to get the value
local function table_to_int(value)
if type(value) ~= "table" then
return tonumber(value)
end
local first_key, first_value = next(value)
if first_value == nil then
return nil
end
return table_to_int(first_value)
end
@sundb I don't know where to check, I am using docker redis-stack-server:lastest .
It's very counter-intuitive and cost me much time to figure out.
Comment From: sundb
because the second reply of TS.REVRANGE is double, please ref Array reply of (Integer reply, Simple string reply) pairs representing (timestamp, value(double)) https://redis.io/docs/latest/commands/ts.revrange/
becausedouble is represented as string in RESP2, but it is a number in RESP3, but in LUA all number type are double, so in order to distinguish between integer and double, we use table to represent double.
local function table_to_int(value)
if type(value) ~= "table" then
return tonumber(value)
end
local first_key, first_value = next(value)
if first_value == nil then
return nil
end
return table_to_int(first_value)
end
you don't need to validate it, instead, you can use value['double'] directly.
Comment From: eromoe
@sundb
result[1][2]['double'] is nil
I have tried
local function get_range_last(keys, args)
local key = args[1]
local start_time = args[2]
local end_time = args[3]
-- TS.REVRANGE qmt:000001.SZ:1m:open 0 1721612760000 1721612760000 COUNT 1 LATEST
local result = redis.call('TS.REVRANGE', key, start_time, end_time, 'COUNT', 1, 'LATEST')
if result and #result > 0 then
return result[1][2]['double']
else
return nil
end
end
127.0.0.1:6379> TS.REVRANGE qmt:000001.SZ:1m:open 0 1721612760000 1721612760000 COUNT 1 LATEST
1) 1) (integer) 1721612760000
2) 10.27
127.0.0.1:6379> FCALL get_range_last 0 qmt:000001.SZ:1m:open 1721612760000 1721612760000
(nil)
Comment From: eromoe
I found the result is {'ok' : value} , this is unconsistent with redis-cli api !
local function print_table(t)
redis.log(redis.LOG_NOTICE, cjson.encode(t))
end
local timestamp = result[1][1]
local value = result[1][2]
print_table(value)
Comment From: sundb
@sundb
result[1][2]['double']is nilI have tried
``` local function get_range_last(keys, args) local key = args[1] local start_time = args[2] local end_time = args[3]
-- TS.REVRANGE qmt:000001.SZ:1m:open 0 1721612760000 1721612760000 COUNT 1 LATEST local result = redis.call('TS.REVRANGE', key, start_time, end_time, 'COUNT', 1, 'LATEST') if result and #result > 0 then return result[1][2]['double'] else return nil endend ```
127.0.0.1:6379> TS.REVRANGE qmt:000001.SZ:1m:open 0 1721612760000 1721612760000 COUNT 1 LATEST 1) 1) (integer) 1721612760000 2) 10.27 127.0.0.1:6379> FCALL get_range_last 0 qmt:000001.SZ:1m:open 1721612760000 1721612760000 (nil)
you confuse the difference between reading it in Lua script and replying it to the client. read it in lua
local d = result[1][2]['double']
reply the double to client
return result[1][2]
Note that the format Lua gives you and the format you give back to Lua is the same, are all RESP3 double.
Comment From: sundb
I found the result is {'ok' : value} , this is unconsistent with redis-cli api !
because you are using RESP2, the simple string format is {ok: <string>}
Comment From: eromoe
@sundb I get it, check by hello find it is proto 2 on redis 7.25 , so resp3 is not enabled by default in latest docker image .
And the display problem in below is also by resp2 ?
- here ts.get display value as double, but fcall return displays as integer (double in actually )
- ts.add the fcall return value to a new key, ts.get that new key would display as double too .
This behaviour is really strange ..
127.0.0.1:6379> ts.get qmtagg:000010.SZ:1m:open
1) (integer) 1721619180000
2) 1.7
127.0.0.1:6379> FCALL get_range_last 0 qmtagg:000010.SZ:1m:open 1721619180000 1721619180000
(integer) 1
Comment From: sundb
@sundb I get it, check by
hellofind it is proto 2 on redis 7.25 , so resp3 is not enabled by default in latest docker image .And the display problem in below is also by resp2 ?
- here
ts.getdisplay value as double, butfcallreturn displays as integer (double in actually )ts.addthefcallreturn value to a new key,ts.getthat new key would display as double too . This behaviour is really strange ..
127.0.0.1:6379> ts.get qmtagg:000010.SZ:1m:open 1) (integer) 1721619180000 2) 1.7 127.0.0.1:6379> FCALL get_range_last 0 qmtagg:000010.SZ:1m:open 1721619180000 1721619180000 (integer) 1
if you want to return double to client , you should return `{double : 1.7}', otherwise, it will be treated as an integer.
Comment From: sundb
@eromoe please also ref https://redis.io/docs/latest/develop/interact/programmability/lua-api/#lua-to-resp3-type-conversion you need to know the lua and redis communication format.
Comment From: eromoe
Thank you very much for explanation, that inconsistent in redis luaenv is really hurt for newbie to lua . I think everyone use lua in redis would enconter this and the display problem, it would be much better to have a trouble shooting chapter in lua section, https://redis.io/docs/latest/develop/interact/programmability/lua-api/ .Because not easy to reach the convertion detail, Google and Stackoverflow don't contain similar questions and the LLMs also reply wrong answers.
Comment From: sundb
@eromoe i'm had been there before, feel free to call me here.