我正在尝试使用 C# StackExchange 库来使用以下 Lua 脚本:
private const string LuaScriptToExecute = @"
local current
current = redis.call(""incr"", KEYS[1])
if current == 1 then
redis.call(""expire"", KEYS[1], KEYS[2])
return 1
else
return current
end
每当我“作为字符串”评估脚本时,它都能正常工作:
var incrementValue = await Database.ScriptEvaluateAsync(LuaScriptToExecute,
new RedisKey[] { key, ttlInSeconds });
如果我正确理解,每次调用 scriptevaluateasync
方法,脚本都会传输到Redis服务器,这不是很有效。
为了克服这一点,我尝试通过运行:
使用“准备好的脚本”方法_setCounterWithExpiryScript = LuaScript.Prepare(LuaScriptToExecute);
...
...
var incrementValue = await Database.ScriptEvaluateAsync(_setCounterWithExpiryScript,
new[] { key, ttlInSeconds });
每当我尝试使用此方法时,都会收到以下错误:
ERR Error running script (call to f_7c891a96328dfc3aca83aa6fb9340674b54c4442): @user_script:3: @user_script: 3: Lua redis() command arguments must be strings or integers
我做错了什么?
使用接收动态参数的“准备好的”LuaScripts 的正确方法是什么?
最佳答案
如果我查看 documentation : 不知道。
如果我查看 unit test on github看起来很简单。
(顺便说一句,您的 ttlInSeconds
真的是 RedisKey
而不是 RedisValue
吗?您正在通过 KEYS[2] 访问它
- 不应该是ARGV[1]
吗?无论如何...)
看来您应该重写脚本以使用命名参数而不是参数:
private const string LuaScriptToExecute = @"
local current
current = redis.call(""incr"", @myKey)
if current == 1 then
redis.call(""expire"", @myKey, @ttl)
return 1
else
return current
end";
// We should load scripts to whole redis cluster. Even when we dont have any.
// In that case, there will be only one EndPoint, one iteration etc...
_myScripts = _redisMultiplexer.GetEndPoints()
.Select(endpoint => _redisMultiplexer.GetServer(endpoint))
.Where(server => server != null)
.Select(server => lua.Load(server))
.ToArray();
然后用匿名类作为参数执行它:
for(var setCounterWithExpiryScript in _myScripts)
{
var incrementValue = await Database.ScriptEvaluateAsync(
setCounterWithExpiryScript,
new {
myKey: (RedisKey)key, // or new RedisKey(key) or idk
ttl: (RedisKey)ttlInSeconds
}
)// .ConfigureAwait(false); // ? ;-)
// when ttlInSeconds is value and not key, just dont cast it to RedisKey
/*
var incrementValue = await
Database.ScriptEvaluateAsync(
setCounterWithExpiryScript,
new {
myKey: (RedisKey)key,
ttl: ttlInSeconds
}
).ConfigureAwait(false);*/
}
警告:
请注意,执行脚本时Redis处于完全停止模式。你的脚本看起来非常简单(你有时会保存一次到 redis 的操作(当 current != 1
时),所以我有一种感觉,这个脚本会在更大的范围内产生反作用。就这样做来自 C# 的一两次调用,不用理会这个脚本。
关于带参数的 Redis StackExchange LuaScripts,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72476693/