有没有可能在redis中调用其他lua脚本中定义的lua函数?
我试图声明一个没有本地关键字的函数,然后从另一个脚本调用这个函数,但是当我运行这个命令时,它给了我一个错误。
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
重要通知:请参阅下面的Josiah的回答。 我的答案是错误的,或者至less是不完整的 。 这让我非常开心,这让Redis更加灵活。
我的错误/不完整的答案:
我很确定这是不可能的。 您不能使用全局variables(阅读文档 ),脚本本身通过Redis Lua引擎获取本地和临时范围。
如果执行任何写操作,Lua函数会在幕后自动设置“写入”标志。 这开始一个交易。 如果您将Lua调用级联,则Redis中的簿记将变得非常麻烦,尤其是在级联在Redis从站上执行时。 这就是为什么EVAL
和EVALSHA
在Lua脚本中故意不能作为有效的Redis调用提供的原因。 调用已经加载的Lua函数也是一样的。 如果在第一个脚本的加载和第二个脚本的执行之间重新启动从站,会发生什么?
我们做什么来克服这个限制:
不要使用EVAL
,只能使用SCRIPT LOAD
和EVALSHA
。 将SHA1存储在redis哈希集合中。
我们在我们的版本控制系统中自动执行了这个操作,所以一个确定的Lua脚本自动将它的SHA1校验和存储在Redis master中,并且使用一个逻辑名称作为哈希集合。 客户端不能使用EVAL(在从属设备上,我们在configuration中禁用了EVAL + LOAD)。 但客户可以要求下一步的SHA1。 几乎我们所有的Lua函数都会为下一个调用返回一个SHA1。
希望这有助于TW
我将违背公认的答案,因为接受的答案是错误的。
虽然无法明确定义命名函数,但您可以调用可以使用EVALSHA
调用的任何脚本。 更具体地说,所有通过SCRIPT LOAD
或通过EVAL
隐式定义的Lua脚本都可以在全局Lua名称空间f_<sha1 hash>
(直到/除非调用SCRIPT FLUSH
),您可以随时调用它。
你遇到的问题是函数被定义为不带参数, KEYS
和ARGV
表实际上是全局的。 所以,如果你想能够在Lua脚本之间进行通信,你需要修改你的KEYS
和ARGV
表,或者你需要使用标准的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)“你好” 2)“世界” 127.0.0.1:6379> eval“KEYS [1] ='blah!'; return f_d006f1a90249474274c76f5be725b8f5804a346b()”1“hello”“world” 1)“blah!” 2)“世界” 127.0.0.1:6379>
所有这一切都说明了这完全违反了规范,如果您尝试在Redis集群scheme中运行此操作,完全可能以奇怪的方式停止工作。
因为我不是一个人,所以我build立了一个允许简单的内部调用语义的包。 该包(用于Python) 在GitHub上可用 。
长话短说,它使用ARGV
作为调用堆栈,将KEYS
/ ARGV
引用翻译为_KEYS
和_ARGV
,在内部使用Redis作为名称 – >哈希映射,并将CALL.<name>(<keys>, <argv>)
转换为一个表追加+ Redis查找+ Lua函数调用。
METHOD.txt
文件描述了发生的事情,我用来翻译Lua脚本的所有正则expression式都可以在lua_call.py
中lua_call.py
。 随意重新使用我的语义。
functionregistry的使用使得在Redis集群或任何其他多分片设置中不太可能工作,但是对于单主应用程序,它应该在可预见的未来工作。