Redis的基于互斥我想实现一个基于内存的多进程共享互斥体,它支持超时,使用Redis的。红宝石 - 与到期实现
我需要该互斥锁是非阻塞的,这意味着我只需要能够知道我是否能够获取互斥锁,如果没有,只需继续执行后备代码即可。
东西沿着这些路线:
if lock('my_lock_key', timeout: 1.minute)
# Do some job
else
# exit
end
的未到期互斥可以采用以下方式实现的Redis的setnx mutex 1
:
if redis.setnx('#{mutex}', '1')
# Do some job
redis.delete('#{mutex}')
else
# exit
end
但是如果我需要一个超时机制互斥(在为了避免在命令redis.delete
之前ruby代码失败的情况,导致该互斥锁永远被锁定,例如,但不仅仅是这个原因)。
做这样的事情显然是行不通的:
redis.multi do
redis.setnx('#{mutex}', '1')
redis.expire('#{mutex}', key_timeout)
end
因为我的到期重新设置为互斥即使我无法设置互斥(setnx
返回0)。
当然,我会预料会有类似于setnxex
的东西,它会以到期时间自动设置密钥的值,但前提是密钥不存在。不幸的是,据我所知,Redis并不支持这一点。
我也不过,找到renamenx key otherkey
,它可以让你重新命名一个关键的一些其他关键,只有在其他关键已不存在。
我想出了这样的事情(用于演示目的,我把它写下来单片,并没有打破它的方法):
result = redis.multi do
dummy_key = "mutex:dummy:#{Time.now.to_f}#{key}"
redis.setex dummy_key, key_timeout, 0
redis.renamenx dummy_key, key
end
if result.length > 1 && result.second == 1
# do some job
redis.delete key
else
# exit
end
在这里,我设置了过期假钥匙,并尝试将其重命名为真钥匙(在一次交易中)。
如果renamenx
操作失败,那么我们无法获取互斥锁,但是没有造成任何损害:虚拟关键字将到期(可以通过添加一行代码立即删除),并且真正的密钥到期时间将保持不变。
如果renamenx
操作成功,那么我们就能够获得互斥体,和互斥将获得所需的到期时间。
任何人都可以看到与上述解决方案的任何缺陷?这个问题是否有更加标准的解决方案?我真的很讨厌使用一个外部的宝石,以解决这个问题...