CharlieShi
CharlieShi

Reputation: 916

redis lua can't work properly due to wrong type comparison

I want to decrease my storage by using redis lua script in python, my code below:

def lua_storage():
conn = redis_conn()
lua = """
        local storage = redis.call('get','storage')
        if  (storage ~= nil) then
            if tonumber(storage) >= 0 then
                return redis.call('decr','storage')
            else
                return 'storage is zero now, can reply decr action'
            end
        else
            redis.call('set','storage',10)
        end
        """
result = conn.eval(lua,0)
print(result)

Above code is simple, it's a lua script to control the good storage, if the good didn't have the storage, the script will set its stroage to 10, when user access this script, the storage will decrease by 1 until to 0. When the storage is 0, then user will get "storage is zero now, can reply decr action" message.

When I ran this method in python, I got below exception:

Traceback (most recent call last):
File "D:/mytools/luaredis/mytest.py", line 53, in <module>
lua_storage()
File "D:/mytools/luaredis/mytest.py", line 47, in lua_storage
result = conn.eval(lua,0)
File "C:\Python27\lib\site-packages\redis\client.py", line 2067, in eval
return self.execute_command('EVAL', script, numkeys, *keys_and_args)
File "C:\Python27\lib\site-packages\redis\client.py", line 668, in execute_command
return self.parse_response(connection, command_name, **options)
File "C:\Python27\lib\site-packages\redis\client.py", line 680, in parse_response
response = connection.read_response()
File "C:\Python27\lib\site-packages\redis\connection.py", line 629, in read_response
raise response
redis.exceptions.ResponseError: Error running script (call to f_19dc8de385a024db32cb227ec869e8b644ebbc36): @user_script:4: user_script:4: attempt to compare number with nil 

I tried to figure out the problem, but couldn't find it out. For the above code itself, I don't think that there are some errors in it(I followed this answer to write my code). The only thing I want to be sure is that, whether the return type for redis and lua is different that caused this exception?

Any good debug method that I should follow to debug this script?

----EDIT----

Thx for my workmate Carol, I changed the code below and got the correct result:

def lua_storage():
conn = redis_conn()
lua = """
        if redis.call('get','storage') then
            if tonumber(redis.call('get','storage')) > 0 then
                return redis.call('decr','storage')
            else
                return 'storage is zero now, can reply decr action'
            end
        else
            redis.call('set','storage',10)
        end
        """
result = conn.eval(lua,0)
print(result)

Here is another problem, we discard the local storage variable, directly used the redis.call('get','storage'). So I don't know why local storage won't do the stuff. Need more work on it.

Thx for Kevin, finally got the code run below:

def lua_storage():
conn = redis_conn()
lua = """
        local storage = redis.call('get','storage')
        if  storage ~= false then
            if tonumber(storage) > 0 then
                return redis.call('decr','storage')
            else
                return 'storage is zero now, can reply decr action'
            end
        else
            return redis.call('set','storage',10)
        end
        """
result = conn.eval(lua,0)
print(result)

Because storage is nil at the first, but put nil in if statement, it will return false, thus we need change nil to false.

Upvotes: 3

Views: 2607

Answers (2)

Carol
Carol

Reputation: 1

The error message explains the issue:

user_script:4: user_script:4: attempt to compare number with nil

Storage is a number can not compared to nil.

The code can be written like this:

"""
          if  redis.call('get','storage') then
            local storage = redis.call('get','storage')
            if tonumber(storage) >= 0 then
                return redis.call('decr','storage')
            else
                return 'storage is zero now, can reply decr action'
            end
        else
            redis.call('set','storage',10)
        end
        """

Upvotes: 0

Kevin Christopher Henry
Kevin Christopher Henry

Reputation: 48952

According to the Redis Lua documentation, a nil Redis value becomes a false Lua value:

Redis Nil bulk reply and Nil multi bulk reply -> Lua false boolean type

Therefore, you should be comparing the result of the GET to false, not nil. You're seeing this particular message because tonumber(false) is nil, which you're then comparing to a number, 0.

Upvotes: 6

Related Questions