I have the following method that waits for an exclusive lock on a Redis key. This method works but I'm wondering if there is a better way without a for loop and a Thread.Sleep.
我有以下方法等待Redis密钥的独占锁。这种方法有效,但我想知道没有for循环和Thread.Sleep是否有更好的方法。
/// <summary>
/// wait up to 2 seconds to achieve a lock!
/// The lock is good for a maximum of 3 seconds
/// </summary>
/// <param name="codeID"></param>
internal void WaitForSingleUseLock(CodeID codeID)
{
var key = _redemptionRepo.SingleUseCodeLockPrefix + codeID.Value;
var expiration = TimeSpan.FromSeconds(3);
for (var i = 0; i < 20; i++)
{
var lockAchieved = _cacheRepo.LockTake(key, "1", expiration);
if (lockAchieved)
{
break;
}
Thread.Sleep(TimeSpan.FromMilliseconds(100));
}
}
2 个解决方案
#1
The only thing I could suggest different would be to consider pub/sub as a side channel (meaning: in addition, not replacement) for indicating when the lock might now be available - i.e. publish when releasing, and use the sub to release a timer (via a monitor or an async-wait-handle).
我唯一可以建议不同的是将pub / sub视为侧面通道(意思是:此外,不是替换),用于指示锁定现在何时可用 - 即释放时发布,并使用sub释放计时器(通过监视器或异步等待句柄)。
Other than that: nope. Redis doesn't have the idea of a pending queue. You could perhaps possibly construct one using lists, but...
除此之外:不。 Redis没有挂起队列的想法。您也许可以使用列表构建一个,但是......
#2
After taking @Marc's comments into consideration and meeting with my team about the benefits of Task.Delay()
over Thread.Sleep()
in this context I decided on this as a final solution:
在考虑了@ Marc的评论并与我的团队讨论了在此上下文中Task.Delay()对Thread.Sleep()的好处之后,我决定将其作为最终解决方案:
/// <summary>
/// wait up to 3 seconds to achieve a lock!
/// The lock is good for a maximum of 3 seconds
///
/// Returns the total amount of time until the lock was taken
/// </summary>
internal virtual async Task<TimeSpan> WaitForSingleUseLock(CodeID codeID)
{
var key = _redemptionRepo.SingleUseCodeLockPrefix + codeID.Value;
var totalTime = TimeSpan.Zero;
var maxTime = TimeSpan.FromSeconds(3);
var expiration = TimeSpan.FromSeconds(3);
var sleepTime = TimeSpan.FromMilliseconds(50);
var lockAchieved = false;
while (!lockAchieved && totalTime < maxTime)
{
lockAchieved = _cacheRepo.LockTake(key, "1", expiration);
if (lockAchieved)
{
continue;
}
await Task.Delay(sleepTime);
totalTime += sleepTime;
}
return totalTime;
}
#1
The only thing I could suggest different would be to consider pub/sub as a side channel (meaning: in addition, not replacement) for indicating when the lock might now be available - i.e. publish when releasing, and use the sub to release a timer (via a monitor or an async-wait-handle).
我唯一可以建议不同的是将pub / sub视为侧面通道(意思是:此外,不是替换),用于指示锁定现在何时可用 - 即释放时发布,并使用sub释放计时器(通过监视器或异步等待句柄)。
Other than that: nope. Redis doesn't have the idea of a pending queue. You could perhaps possibly construct one using lists, but...
除此之外:不。 Redis没有挂起队列的想法。您也许可以使用列表构建一个,但是......
#2
After taking @Marc's comments into consideration and meeting with my team about the benefits of Task.Delay()
over Thread.Sleep()
in this context I decided on this as a final solution:
在考虑了@ Marc的评论并与我的团队讨论了在此上下文中Task.Delay()对Thread.Sleep()的好处之后,我决定将其作为最终解决方案:
/// <summary>
/// wait up to 3 seconds to achieve a lock!
/// The lock is good for a maximum of 3 seconds
///
/// Returns the total amount of time until the lock was taken
/// </summary>
internal virtual async Task<TimeSpan> WaitForSingleUseLock(CodeID codeID)
{
var key = _redemptionRepo.SingleUseCodeLockPrefix + codeID.Value;
var totalTime = TimeSpan.Zero;
var maxTime = TimeSpan.FromSeconds(3);
var expiration = TimeSpan.FromSeconds(3);
var sleepTime = TimeSpan.FromMilliseconds(50);
var lockAchieved = false;
while (!lockAchieved && totalTime < maxTime)
{
lockAchieved = _cacheRepo.LockTake(key, "1", expiration);
if (lockAchieved)
{
continue;
}
await Task.Delay(sleepTime);
totalTime += sleepTime;
}
return totalTime;
}