如何进行延续并将其作为MULTI命令的一部分包含在内?

时间:2015-02-27 12:12:23

标签: c# .net asynchronous redis stackexchange.redis

总之,我正在尝试调用ITransaction.SetPopAsync(...)并执行其他写操作,作为基础MULTI Redis原子操作的一部分。

我尝试执行SetPopAsync(...)调用Task.ContinueWith的延续,并在回调中执行所谓的其他写操作,但当我发现这些操作在执行后执行时我感到很惊讶基础MULTI操作结束(即ITransaction.ExecuteAsync()完成时)。

也许我错了,但我觉得只有当我将一个LUA脚本加载到Redis并且我用C#调用它时,才能完成这个原子操作。

我的案例中是否还有其他解决方案可以在C#和StackExchange.Redis库中完全实现?

更多信息......

我发现有关于此主题的特定文档here

现在我更加困惑因为*如果你执行整个spop并且它不是MULTI命令的一部分,并且当你在{{1}之后创建其他密钥时会发生什么,系统停机并使数据损坏?

所以...我错过了一些可以让我执行整个spop并确保所有其他操作都要完成并保持下去的内容吗?

示例场景......

正如@BerinLoritsch在这里要求一些评论,我将使用Redis命令抛出一个伪代码来举例说明这里发生了什么:

spop

注意我不能使用MULTI key1MemberValue = spop key1 1 sadd key2 key1MemberValue zadd key3 1 key1MemberValue EXEC ,因为我不知道我的真实案例中的集合成员。我需要随机弹出一个。

2 个答案:

答案 0 :(得分:2)

最终,您需要了解redis multi / exec块与ADO.NET事务不同。从根本上说,以下(来自问题)在redis中是不可能的

MULTI
key1MemberValue = spop key1 1

sadd key2 key1MemberValue 
zadd key3 1 key1MemberValue 
EXEC

因为您从spop返回的内容是:QUEUED。就这样。在EXEC之前,您没有得到任何答案,因此无法sadd / zadd内使用此值MULTI

你可以在原始redis中可以想象的是WATCH;但是,所有这些意味着如果WATCH - ed键被另一个连接变异,则MULTI / EXEC块被放弃,而不是执行;你仍然拥有spop - ped。

所以从根本上说:是的,如果你希望在没有竞争连接使状态失效的情况下发生这种情况:你必须通过Lua和EVAL / EVALSHA来完成 - 或者它需要更改{{ 1}} API。

答案 1 :(得分:0)

现在,实际上在我的特定情况下,还有另一种解决同一问题的方法,它允许我以原子性进行操作。

不使用spop,而是使用Redis命令检查以下伪代码:

time = [current time]
member = zrangebyscore key1 -inf +inf limit 0 1

zrem key1 member
zadd key2 time member
zadd key3 time member

现在看来,最佳解决方案似乎是一个LUA脚本,它调用上面的代码列表的命令,因为Redis是单线程的,它可以一次发生一个操作,LUA脚本被认为是一个操作本身,如果我想确保其他操作不会尝试弹出相同的set值,我觉得这应该是要走的路......

此外,我必须将常规集转换为排序集。由于Redis在复制和集群环境中避免数据损坏的限制,因此无法在非确定性命令之后调用写命令,无论是读操作还是写操作。感谢zrangebyscore(它可能是zrangezrevrangezrevrangebyscore ...),因为它是确定性的,我可以模拟< em> pop 操作,仍然使用set语义。