是否可以在redis中调用其他lua脚本中定义的lua函数?

时间:2014-02-12 03:54:22

标签: node.js lua redis

我试图声明一个没有local关键字的函数,然后从另一个脚本调用该函数,但是当我运行命令时它会给我一个错误。

test = function ()    
    return 'test'
end



# from some other script
test()

编辑:

我无法相信我仍然没有答案。我将详细介绍我的设置。

我正在使用带有redis-scripto包的节点将脚本加载到redis中。这是一个例子。

var Scripto = require('redis-scripto');
var scriptManager = new Scripto(redis);

scriptManager.loadFromDir('./lua_scripts');

var keys    = [key1, key2];
var values  = [val];

scriptManager.run('run_function', keys, values, function(err, result) {
console.log(err, result)
})

和lua脚本。

-- ./lua_scripts/dict_2_bulk.lua

-- turns a dictionary table into a bulk reply table
dict2bulk = function (dict)
    local result = {}
    for k, v in pairs(dict) do
        table.insert(result, k)
        table.insert(result, v)
    end
    return result
end


-- run_function.lua 

return dict2bulk({ test=1 })

引发以下错误。

[Error: ERR Error running script (call to f_d06f7fd783cc537d535ec59228a18f70fccde663): @enable_strict_lua:14: user_script:1: Script attempted to access unexisting global variable 'dict2bulk' ] undefined

3 个答案:

答案 0 :(得分:5)

我会接受已接受的答案,因为接受的答案是错误的。

虽然您无法明确定义命名函数,但可以调用可以使用EVALSHA调用的任何脚本。更具体地说,您通过SCRIPT LOAD或通过EVAL隐式定义的所有Lua脚本都可以在f_<sha1 hash>的全局Lua命名空间中使用(除非您调用SCRIPT FLUSH }),你可以随时打电话。

您遇到的问题是函数被定义为不带参数,KEYSARGV表实际上是全局变量。因此,如果您希望能够在Lua脚本之间进行通信,则需要修改KEYSARGV表,或者需要使用标准Redis键空间来进行函数之间的通信。

127.0.0.1:6379> script load "return {KEYS[1], ARGV[1]}"
"d006f1a90249474274c76f5be725b8f5804a346b"
127.0.0.1:6379> eval "return f_d006f1a90249474274c76f5be725b8f5804a346b()" 1 "hello" "world"
1) "hello"
2) "world"
127.0.0.1:6379> eval "KEYS[1] = 'blah!'; return f_d006f1a90249474274c76f5be725b8f5804a346b()" 1 "hello" "world"
1) "blah!"
2) "world"
127.0.0.1:6379>

所有这些都说明了,这完全违反了规范,如果你试图在Redis集群场景中运行它,完全有可能以奇怪的方式停止工作。

答案 1 :(得分:1)

重要提示:请参阅下面的Josiah的回答。我的答案结果是错误或至少不完整。这让我非常高兴,这让Redis变得更加灵活。

我的错误/不完整答案:

我很确定这是不可能的。您不能使用全局变量(阅读docs),并且脚本本身由Redis Lua引擎获取本地和临时范围。

如果Lua函数执行任何写操作,它们会在幕后自动设置“写入”标志。这会启动一个事务。如果您级联Lua调用,Redis中的簿记将变得非常麻烦,尤其是在Redis从站上执行级联时。这就是为什么EVALEVALSHA有意无法作为Lua脚本中的有效Redis调用而可用的原因。调用已经尝试执行的已经“加载”的Lua函数也是如此。如果在第一个脚本的加载和第二个脚本的exec之间重新启动从属设备会发生什么?

我们如何克服这一限制:

请勿使用EVAL,仅使用SCRIPT LOADEVALSHA。 将SHA1存储在redis哈希集中。

我们在版本控制系统中对此进行了自动化,因此提交的Lua脚本会自动获取存储在Redis主服务器中的SHA1校验和,并使用逻辑名称存储在哈希集中。客户端无法使用EVAL(在从服务器上;我们在配置中禁用了EVAL + LOAD)。但是客户端可以在下一步请求SHA1。几乎所有的Lua函数都为下一次调用返回一个SHA1。

希望这有帮助,TW

答案 2 :(得分:0)

因为我不能单独留下足够好的东西,所以我构建了一个允许简单内部调用语义的包。包(适用于Python)可用on GitHub

长话短说,它使用ARGV作为调用堆栈,将KEYS / ARGV引用转换为_KEYS_ARGV,使用Redis作为名称 - &GT;内部哈希映射,并将CALL.<name>(<keys>, <argv>)转换为表追加+ Redis查找+ Lua函数调用。

METHOD.txt文件描述了发生了什么,我用来翻译Lua脚本的所有正则表达式都可以在lua_call.py中找到。随意重用我的语义。

使用函数注册表使得非常不太可能在Redis集群或任何其他多分片设置中工作,但对于单主应用程序,它应该在可预见的未来工作。