带参数的 Redis StackExchange LuaScripts

标签 redis lua stackexchange.redis

我正在尝试使用 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/

相关文章:

redis - StackExchange.Redis 的 SETNX 超时

redis - 为什么建议不要在 Redis 中使用 KEYS?

php - 通过Redis Hash存储和查找

c - 删除使用 lua_newuserdata 分配的内存

sorting - Lua表排序2比较

redis - HMSET 和字段值

asp.net-mvc - 如何将客户类对象数据存储到 Redis 缓存中?

redis - 如何在redis中为特定命令配置fsync

performance - Redis 的端口与套接字

lua - 强制 SWIG 生成 Lua 包装器以允许 varargs 函数使用额外参数