redlock-rb
redlock-rb copied to clipboard
Restart redis than get Redis::CommandError: NOSCRIPT No matching script. Please use EVAL.
Hello redlock team,
I just started to use redlock yesterday.
After I restart my redis server, I get this error when using Redlock::Client lock
Redis::CommandError: NOSCRIPT No matching script. Please use EVAL.'
/usr/local/bundle/gems/redlock-2.0.6/lib/redlock/client.rb:323:in `lock_instances'
/usr/local/bundle/gems/redlock-2.0.6/lib/redlock/client.rb:275:in `block in try_lock_instances'
/usr/local/bundle/gems/redlock-2.0.6/lib/redlock/client.rb:271:in `times'
/usr/local/bundle/gems/redlock-2.0.6/lib/redlock/client.rb:271:in `try_lock_instances'
/usr/local/bundle/gems/redlock-2.0.6/lib/redlock/client.rb:79:in `lock'
It seems redis cannot find the script. Do you know how to fix this?
Thanks, Larry
I had the exact same issue. After debugging for a few hours, I found that this was due to a change in Redlock::Client::RedisInstance#recover_from_script_flush
that was made when updating the gem from version 1.3.2
to 2.x.x
. The change was to catch the RedisClient::CommandError
error and not Redis::CommandError
. However, the exception object was still Redis::CommandError
with the following combination, causing the exception to be passed through to the next clause then just raised. This error reproduces only after restarting the Redis server or invoking SCRIPT FLUSH SYNC
to clear the cache.
- redis 4.8.1 / 5.0.8
- redis-client 0.18.0 / 0.19.0
As for the solution, I downgraded the gem to 1.3.2
temporarily. Alternatively, I confirmed that the following monkey patch worked, but we did not use it on our production environment.
# config/initializers/redlock.rb
module Redlock
class Client
private
class RedisInstance
private
def recover_from_script_flush
retry_on_noscript = true
begin
yield
rescue RedisClient::CommandError, Redis::CommandError => e # <= ADDED Redis::CommandError
# When somebody has flushed the Redis instance's script cache, we might
# want to reload our scripts. Only attempt this once, though, to avoid
# going into an infinite loop.
if retry_on_noscript && e.message.include?('NOSCRIPT')
load_scripts
retry_on_noscript = false
retry
else
raise
end
end
end
end
end
end
Wouldn't the "recommended" fix be, to use redis-client
to configure redlock. So instead of passing an instance of Redis
to Redlock.new
, use RedisClient
?
Note that you would probably need redis 6+ with RESP3 support.
Thank you @jakephot for the monkey-patch! It saved my day. I wonder why this bug is still not solved though.
Hmm, in my case I didn't need the entire monkey-patch. I was already trying to rescue Redis::CommandError
so adding RedisClient::CommandError
there helped. Seems like the errors are not unified somewhere.