I tried executing the below erroneous eval command to understand the difference between redis.call() and redis.pcall()
eval "return redis.call(ARGV[2],KEYS[1])" 1 key get
eval "return redis.pcall(ARGV[2],KEYS[1])" 1 key get
In both the cases, i got the error below,
(error) Lua redis() command arguments must be strings or integers
This error doesn't convey the difference between redis.call() and redis.pcall() as illustrated by the documentation which says
" redis.call() is similar to redis.pcall(), the only difference is that if a Redis command call will result into an error, redis.call() will raise a Lua error that in turn will force EVAL to return an error to the command caller, while redis.pcall will trap the error returning a Lua table representing the error."
So according to the documentation , in the case of using redis.pcall() the error should be trapped , right! In that case why are both the errors same?? If i have misconstrued the difference, it would be better if someone could clearly illustrate the difference between the commands!!
This is a tricky case because in you example the command does not generate the error, you are using redis.call
and redis.pcall
incorrectly (because ARGV[2]
is nil
like the error message is telling you). So in both cases the error is not recovered.
Here is an example where the command actually fails and you can see the difference:
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)
However, you may notice that I did not return the result of pcall
, so the script returns nil
. What if I return the result of an erroneous command?
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
With call
nothing changes because the error (think of it like an exception in other languages - Java, Python, etc) is thrown before the function has a chance to return anyway.
With pcall
though, the function call returns a table with a single err
field which is converted to an "Error reply" by Redis, so you do not see it. How can you check that? Linearize it!
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"
It fails because Redis cannot perform the call or pcall command. I mean it fails before the actual Redis command (here, it is a get command) is executed. pcall will catch errors during the execution of the Redis command, not during the execution of pcall itself.
Let's modify your input so that that the Redis command fails (and not the redis.call command itself).
> 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
You can see on the second call the Redis error result in a Lua error.
On the third call, pcall is used instead, so the result is not anymore a Lua error, but simply an output string containing the text of the error.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With