【问题标题】:Illustrating the difference between redis.call() and redis.pcall()说明 redis.call() 和 redis.pcall() 之间的区别
【发布时间】:2014-01-06 15:54:56
【问题描述】:

我尝试执行以下错误的 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() 的情况下,错误应该被捕获,对吧!在那种情况下,为什么两个错误都一样?如果我误解了区别,如果有人能清楚地说明命令之间的区别会更好!

【问题讨论】:

    标签: lua redis eval


    【解决方案1】:

    失败是因为 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 错误,而只是一个包含错误文本的输出字符串。

    【讨论】:

    • 我们的响应之间的竞争条件 :)
    • 是的……不过你的更完整!
    【解决方案2】:

    这是一个棘手的情况,因为在您的示例中,该命令不会生成错误,您错误地使用了redis.callredis.pcall(因为ARGV[2]nil,就像错误消息告诉您的那样)。所以在这两种情况下,错误都没有恢复。

    这是一个 command 实际失败的示例,您可以看到不同之处:

    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"
    

    【讨论】:

    • 很好的答案!!
    猜你喜欢
    • 2014-02-23
    • 1970-01-01
    • 2023-04-03
    • 2012-10-01
    • 1970-01-01
    • 2016-04-20
    • 1970-01-01
    • 2012-04-09
    • 2016-05-04
    相关资源
    最近更新 更多