StringSetAsync с When.NotExists возвращает false, если ключ не существует

Я использую StackExchange.Redis с кластером реплик (3 узла), настроенным на использование Sentinel.

Я получаю несколько запросов, пытаясь обновить кеш одними и теми же данными, поэтому, чтобы избежать многократной записи, я использую When.NotExists в StringSetAsync. Насколько я понимаю, это предотвратит установку, если ключ уже существует. Я ожидаю, что StringSetAsync вернет true только в тех случаях, когда набор действительно произошел.

Пример:

var inserted = await connectionMultiplexer.GetDatabase().StringSetAsync("my-key", "my-value", myTimeout, When.NotExists);

if(inserted == false)
{
  var keyExists = await connectionMultiplexer.GetDatabase().KeyExistsAsync("my-key");
  if(keyExists == false)
  {
    // I end up here, which I assumed should not happen. 
  }
}

К моему удивлению, я вижу, что StringSetAsync возвращает false, даже если ключ еще не существует на основе проверки работоспособности, когда я вручную проверяю наличие ключа.

Примечания. В моей среде используются 2 узла-реплики и один основной. StackExchange.Redis версия: 2.1.58


person TGH    schedule 05.10.2020    source источник
comment
Видите ли вы такое же поведение с кластером из одного узла?   -  person DylanSp    schedule 08.10.2020
comment
Вы проверили, что кластеры Redis работают?   -  person Saeed Esmaeelinejad    schedule 14.10.2020


Ответы (1)


Что я обычно делаю в таких случаях, так это временно увеличиваю параметр expiry (myTimeout) до большего значения просто для того, чтобы убрать тайм-аут из уравнения. Следующими шагами будет проверка прав доступа для всех системных границ между вашим приложением и сервером базы данных.

Также имейте в виду, что если операция выдает исключение из-за тайм-аута или другого рода сбоя, в зависимости от того, как вы применяете стек async/await, в некоторых случаях исключение тайм-аута не может быть выдано вызывающему потоку, и вы необходимо запросить агрегат Task.Exception, чтобы проверить источник проблемы.

Мне кажется подозрительным, что результатом является false (значение по умолчанию для boolean) и потенциально у вас есть ответ на вашу проблему в совокупности Task.Exception.

Чтобы узнать, вы можете попробовать это синхронно:

try
{
    var inserted = connectionMultiplexer.GetDatabase().StringSetAsync("my-key", "my-value", myTimeout, When.NotExists).Result;
    if (inserted == false)
    {
        var keyExists = connectionMultiplexer.GetDatabase().KeyExistsAsync("my-key").Result;
        if (keyExists == false)
        {
            // I end up here, which I assumed should not happen. 
        }
    }
}
catch (AggregateException aex)
{
    foreach (var ex in aex.InnerExceptions)
    {
        Console.WriteLine(ex);
    }
}

Пожалуйста, скажите мне, как это происходит!

person Lucky Brain    schedule 08.10.2020