Обработка исключений Azure Redis Cache - PullRequest
0 голосов
/ 15 мая 2019

Я использую Redis Cache Azure для разработки и хотел проверить способ обработки исключений. В соответствии с лучшими практиками, можно столкнуться с исключениями RedisConnectionException и, чтобы решить эту проблему, мы должны избавиться от старого ConnectionMultiplexer и создать новый. Если для abortConnect установлено значение false, мультиплексор будет молча повторять попытку подключения, не выдавая ошибку. Так что, если исключение выдается, оно будет только после нескольких попыток восстановить и все еще не удалось. Правильно ли мое понимание этого? Это моя строка подключения -

cachename.redis.cache.windows.net:6380,password=Password,ssl=True,abortConnect=False

Я полагаю, что исключение подключения произойдет только при попытке вызвать GetConnection () на мультиплексоре. Найдите мой код ниже -

    static Lazy<ConnectionMultiplexer> multiplexer = CreateMultiplexer();

    public static ConnectionMultiplexer GetConnection() => multiplexer.Value;

    private static Lazy<ConnectionMultiplexer> CreateMultiplexer()
    {
        return new Lazy<ConnectionMultiplexer>(() => ConnectionMultiplexer.Connect(connectionString));
    }

    private static void CloseMultiplexer(Lazy<ConnectionMultiplexer> oldMultiplexer)
    {
        if (oldMultiplexer != null)
        {
            oldMultiplexer.Value.Close();
        }
    }

    public static void Reconnect()
    {
        var oldMultiplexer = multiplexer;
        CloseMultiplexer(multiplexer);
        multiplexer = CreateMultiplexer();
    }

И я потребляю это ниже в другом классе -

    public class RedisCacheManager
    {
        private static IDatabase _cache;

        private TimeSpan expiry = new TimeSpan(hours: 6, minutes: 0, seconds: 0);

        public RedisCacheManager()
        {
            try
            {
                _cache = RedisCacheHelper.GetConnection().GetDatabase();
            }
            catch(RedisConnectionException)
            {
                RedisCacheHelper.Reconnect();
                new RedisCacheManager();
            }
        }

        public async Task<RedisValue[]> GetFromCacheAsync(List<string> keys)
        {
            var cacheValues = await _cache.StringGetAsync(keys.Select(k => (RedisKey)k).ToArray());
            return cacheValues;
        }

        public async Task SaveInCacheAsync<TValue>(Dictionary<string, TValue> kvps)
        {
            var tasks = new List<Task>();

            foreach(var kvp in kvps)
            {
                tasks.Add(_cache.StringSetAsync(kvp.Key, JsonConvert.SerializeObject(kvp), expiry));
            }
            await Task.WhenAll(tasks);
        }
        }

Я не уверен, что id, вызывающий конструктор в блоке catch, является хорошей практикой. И есть ли другие исключения, которые мне нужно будет обработать при вызове StringGetAsync и StringSetAsync?

1 Ответ

0 голосов
/ 17 мая 2019

CacheManager может выглядеть следующим образом:

using Newtonsoft.Json;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

public sealed class RedisCacheManager : IDisposable
{
    private readonly TimeSpan _expiry;

    private readonly Lazy<ConnectionMultiplexer> _lazyConnection;

    private ConnectionMultiplexer Connection { get => _lazyConnection.Value; }

    public RedisCacheManager(string connectionString, TimeSpan expiry)
    {
        _expiry = expiry;

        _lazyConnection = new Lazy<ConnectionMultiplexer>(() => ConnectionMultiplexer.Connect(connectionString));
    }

    public async Task<RedisValue[]> GetFromCacheAsync(IEnumerable<string> keys)
    {
        var cacheValues = await Connection.GetDatabase()
          .StringGetAsync(keys.Select(key => (RedisKey)key).ToArray()).ConfigureAwait(false);
        return cacheValues;
    }

    public async Task SaveInCacheAsync<TValue>(Dictionary<string, TValue> kvps)
    {
        var tasks = kvps
            .Select(kvp => Connection.GetDatabase().StringSetAsync(kvp.Key, JsonConvert.SerializeObject(kvp), _expiry))
            .ToArray();

        await Task.WhenAll(tasks).ConfigureAwait(false);
    }

    public void Dispose()
    {
        if (_lazyConnection.IsValueCreated)
        {
            _lazyConnection.Value.Dispose();
        }
    }
}

Использование:

public readonly static RedisCacheManager RedisCacheManager = new RedisCacheManager("connection string", TimeSpan.FromHours(6));

Замечания:

  • предполагается, что abortConnect = false (что означает, что вызов завершается успешно, даже если не установлено соединение с кэшем Azure для Redis), и из конструктора не должно создаваться никаких исключений Redis

  • Объект, возвращаемый из GetDatabase, является дешевым сквозным объектом , и его не нужно хранить.

  • GetFromCacheAsync / SaveInCacheAsync -методы могут генерировать исключение извне, и это нормально.Вы можете применить Retry-policy для разрешения временных сбоев.

  • Если у вас есть какой-либо IoC-контейнер, тогда он должен создать RedisCacheManager с однимобласть действия экземпляра (например, регистрация Autofac )

...