说明redis.call()和redis.pcall()之间的区别

时间:2013-12-18 12:47:35

标签: lua redis eval

我尝试执行以下错误的eval命令来理解redis.call()和redis.pcall()之间的区别

eval "return redis.call(ARGV[2],KEYS[1])" 1 key get   
eval "return redis.pcall(ARGV[2],KEYS[1])" 1 key get

在这两种情况下,我都收到了以下错误,

(error) Lua redis() command arguments must be strings or integers

此错误并未传达redis.call()和redis.pcall()之间的区别,如文档所示

" redis.call()类似于redis.pcall(),唯一的区别是如果Redis命令调用将导致错误,redis.call()将引发Lua错误,反过来会强制EVAL返回错误到命令调用者,而redis.pcall将捕获错误,返回表示错误的Lua表。"

所以根据文档,在使用redis.pcall()的情况下,错误应该被困住,对吧!在那种情况下为什么两个错误都相同?如果我误解了差异,那么如果有人能够清楚地说明命令之间的区别就会更好!!

2 个答案:

答案 0 :(得分:12)

这是一个棘手的情况,因为在您的示例中,命令不会生成错误,您正在使用redis.callredis.pcall错误(因为ARGV[2]nil错误消息告诉你)。因此,在这两种情况下都不会恢复错误。

以下是命令实际失败的示例,您可以看到差异:

redis 127.0.0.1:6379> set foo bar
OK
redis 127.0.0.1:6379> eval 'redis.call("hget","foo","bar")' 0
(error) ERR Error running script (call to f_9e6d82f0740926e0a70775430bda59a54d4e0664): ERR Operation against a key holding the wrong kind of value
redis 127.0.0.1:6379> eval 'redis.pcall("hget","foo","bar")' 0
(nil)

但是,您可能会注意到我没有返回pcall的结果,因此脚本会返回nil。如果我返回错误命令的结果怎么办?

redis 127.0.0.1:6379> eval 'return redis.call("hget","foo","bar")' 0
(error) ERR Error running script (call to f_d0a8dce7264708876edf262052788fc90a8e8325): ERR Operation against a key holding the wrong kind of value
redis 127.0.0.1:6379> eval 'return redis.pcall("hget","foo","bar")' 0
(error) ERR Operation against a key holding the wrong kind of value

call没有任何变化,因为在函数有机会返回之前,会抛出错误(将其视为其他语言中的异常 - Java,Python等)。

但是使用pcall时,函数调用返回一个带有单个err字段的表,该字段由Redis转换为“错误回复”,因此您看不到它。你怎么检查?线性化它!

redis 127.0.0.1:6379> eval 'local t = redis.pcall("hget","foo","bar"); local r = {type(t)}; for k,v in pairs(t) do r[#r+1] = k; r[#r+1] = v; end; return r' 0
1) "table"
2) "err"
3) "ERR Operation against a key holding the wrong kind of value"

答案 1 :(得分:3)

失败,因为Redis无法执行call或pcall命令。我的意思是它在执行实际的Redis命令(这里是一个get命令)之前失败了。 pcall将在执行Redis命令期间捕获错误,而不是在执行pcall本身期间捕获错误。

让我们修改您的输入,以便Redis命令失败(而不是redis.call命令本身)。

> EVAL "return redis.call(ARGV[1],KEYS[1])" 1 key get
"100"

> EVAL "return redis.call(ARGV[1],KEYS[1])" 1 key born_to_fail
(error) ERR Error running script (call to f_2673dc91ae540aa65dedd262a952d5338e330b37): @user_script:1: @user_script: 1: Unknown Redis command called from Lua script

> EVAL "return redis.pcall(ARGV[1],KEYS[1])" 1 key born_to_fail
(error) @user_script: 1: Unknown Redis command called from Lua script

您可以在第二次调用时看到Redis错误导致Lua错误。

在第三次调用时,改为使用pcall,因此结果不再是Lua错误,而只是包含错误文本的输出字符串。