Lua redis()命令参数必须是字符串或整数--但是同一命令在redis-redis提示符下有效

gfttwv5a  于 2023-10-15  发布在  Redis
关注(0)|答案(1)|浏览(194)

有一个命令,它可以在我的Redis Azure Cache“redis-task”提示符下完美工作(启用了TimeSeries模块的Enterprise E10示例):

EVAL "redis.call('TS.ADD', KEYS[1], '*', ARGV[1], 'RETENTION', ARGV[2], 'ON_DUPLICATE', 'SUM', 'ENCODING', 'UNCOMPRESSED'); return redis.call('TS.RANGE', KEYS[1], '-', '+')" 1 key1 1 1800000
1) 1) (integer) 1693323424958
   2) 1
2) 1) (integer) 1693323485951
   2) 1
3) 1) (integer) 1693323528702
   2) 1
4) 1) (integer) 1693323531678
   2) 1

正如您所看到的,我已经调用了4次,这增加了4个时间戳,所有时间戳的值都是“key 1”时间序列的1。
然而,当我尝试在一个简单的C# .Net控制台应用程序中调用相同的命令时:

private static readonly TimeSpan RETENTION_TIME = TimeSpan.FromMinutes(30);

private const string LUA_SCRIPT = @"redis.call('TS.ADD', KEYS[1], '*', ARGV[1], 'RETENTION', ARGV[2], 'ON_DUPLICATE', 'SUM', 'ENCODING', 'UNCOMPRESSED'); return redis.call('TS.RANGE', KEYS[1], '-', '+')";

private static async Task<int> AddTimestampReturnSumAsync(IDatabase db, string key, int retentionTime)
{
    RedisResult result = await db.ScriptEvaluateAsync(LUA_CMD, new RedisKey[] { key }, new RedisValue[] { retentionTime });
    Console.WriteLine(JsonSerializer.Serialize(result));
    return 0; // a placeholder, I actually want to return a sum of the values
}

然后是下面这行:

int sum = await AddTimestampReturnSumAsync(redis.GetDatabase(), "key1", (int)RETENTION_TIME.TotalMilliseconds);

失败并显示
StackExchange.Redis.RedisServerException:'ERR运行脚本时出错(调用f_503fcb14af1e60051a54d3617d5265f753dfe423):@user_script:1:@user_script:1:Lua redis()命令参数必须是字符串或整数

为了调试这个问题,我尝试了以下2个字符串,它们只是按预期工作:

private const string LUA_SCRIPT = @"return KEYS[1]"; // returns a RedisResult with "key1"

private const string LUA_SCRIPT = @"return ARGV[1]"; // returns a RedisResult with 1800000

问题可能出在Lua代码中吗?
我只是试图从我的C#应用程序中调用TS.ADDTS.RANGE作为单个原子单元。
目前,我正在学习ScriptingTests.cs,试图了解我的代码有什么不同。

w6mmgewl

w6mmgewl1#

我在GitHub上得到了a helpful comment,关于我在Lua代码中使用ARGV[2],而我只为ScriptEvaluateAsync()的C#调用提供了一个参数。
经过一些时间序列的挣扎,我最终的Lua源代码看起来像这样:

// The script returns 0 if there are 20 or more timestamps in the past 30 min (1800000 ms).
// Otherwise it adds a new timestamp to the time series at the key and returns 1.
private const string LUA_SCRIPT =
@"
local sum = 0
local now = redis.call('TIME')
-- the start timestamp for TS.RANGE command in milliseconds
local start = now[1] * 1000 + now[2] / 1000 - ARGV[1]
local tsrange = redis.call('TS.RANGE', KEYS[1], start, '+')

for i = 1, #tsrange do
    -- calculate a sum of all values stored in the time series, from start to now
    sum = sum + tsrange[i][2]['ok']

    -- if there are enough timestamps in the time period, then just return 0
    if (sum >= 20) then
        return 0
    end
end

-- otherwise add the current timestamp and the value 1 to the time series
redis.call('TS.ADD', KEYS[1], '*', 1, 'RETENTION', ARGV[1], 'ON_DUPLICATE', 'SUM', 'ENCODING', 'UNCOMPRESSED')
return 1
";

C#调用在这里:

private static async Task<bool> AddTimestampAsync(IDatabase db, string key, long retentionTime)
{
    RedisResult result = await db.ScriptEvaluateAsync(LUA_SCRIPT, new RedisKey[] { key }, new RedisValue[] { retentionTime });
    // return true if the Lua script returns 1, otherwise false
    return result.Type == ResultType.Integer && (int)result == 1;
}

相关问题