【问题标题】:redis lua can't work properly due to wrong type comparison由于类型比较错误,redis lua 无法正常工作
【发布时间】:2018-06-13 17:46:44
【问题描述】:

我想通过在 python 中使用 redis lua 脚本来减少存储空间,我的代码如下:

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)

上面的代码很简单,就是一个lua脚本来控制好存储,如果好没有存储,脚本会设置stroage为10,当用户访问这个脚本时,存储会减1,直到为0。当storage为0时,用户会收到“storage is zero now, can reply decr action”信息。

当我在 python 中运行这个方法时,我得到了以下异常:

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 

我试图找出问题所在,但找不到。 对于上面的代码本身,我不认为其中有什么错误(我是跟着this answer写我的代码)。我唯一要确定的是,redis 和 lua 的返回类型是否不同导致了这个异常?

我应该遵循什么好的调试方法来调试这个脚本?

----编辑----

感谢我的同事 Carol,我更改了下面的代码并得到了正确的结果:

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)

这里还有一个问题,我们丢弃了local storage变量,直接使用了redis.call('get','storage')。 所以我不知道为什么本地存储不能做这些事情。需要更多的工作。

感谢 Kevin,终于可以运行下面的代码了:

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)

因为一开始storage是nil,但是把nil放在if语句中,它会返回false,所以我们需要把nil改成false。

【问题讨论】:

    标签: lua redis


    【解决方案1】:

    根据Redis Lua documentation,一个nil Redis 值变成了一个false Lua 值:

    Redis Nil 批量回复和 Nil 多批量回复 -> Lua false boolean 类型

    因此,您应该将GET 的结果与false 进行比较,而不是nil。您看到此特定消息是因为 tonumber(false)nil,然后您将其与数字 0 进行比较。

    【讨论】:

      【解决方案2】:

      错误消息解释了问题:

      user_script:4: user_script:4: 尝试将数字与 nil 进行比较

      存储是一个无法与 nil 相比的数字。

      代码可以这样写:

      """
                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
              """
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-13
        • 2020-03-03
        • 1970-01-01
        • 2019-07-10
        • 1970-01-01
        相关资源
        最近更新 更多