StackExchange.Redis — лучший способ дождаться блокировки

У меня есть следующий метод, который ожидает эксклюзивной блокировки ключа 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));
        }
    }

person jhilden    schedule 07.05.2015    source источник


Ответы (2)


Единственное, что я мог бы предложить по-другому, это рассматривать pub/sub как побочный канал (имеется в виду: кроме того, не замена) для указания, когда блокировка может теперь быть доступной, т. е. публиковать при освобождении, и используйте подпрограмму для запуска таймера (через монитор или дескриптор асинхронного ожидания).

Кроме этого: нет. В Redis нет идеи очереди ожидания. Возможно, вы могли бы возможно построить его, используя списки, но...

person Marc Gravell    schedule 07.05.2015

Приняв во внимание комментарии @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;
    }
person jhilden    schedule 08.05.2015