Webiant Logo Webiant Logo
  1. No results found.

    Try your search with a different keyword or use * as a wildcard.

RedisConnectionWrapper.cs

using System.Net;
using Microsoft.Extensions.Caching.StackExchangeRedis;
using Microsoft.Extensions.Options;
using StackExchange.Redis;

namespace Nop.Services.Caching;

/// 
/// Redis connection wrapper
/// 
/// 
/// This class should be registered on IoC as singleton instance
/// 
public partial class RedisConnectionWrapper : IRedisConnectionWrapper
{
    #region Fields

    protected readonly SemaphoreSlim _connectionLock = new(1, 1);
    protected volatile IConnectionMultiplexer _connection;
    protected readonly RedisCacheOptions _options;

    #endregion

    #region Ctor

    public RedisConnectionWrapper(IOptions optionsAccessor)
    {
        _options = optionsAccessor.Value;
    }

    #endregion

    #region Utilities

    /// 
    /// Create a new ConnectionMultiplexer instance
    /// 
    /// 
    protected virtual async Task ConnectAsync()
    {
        IConnectionMultiplexer connection;

        if (_options.ConnectionMultiplexerFactory is null)
        {
            if (_options.ConfigurationOptions is not null)
                connection = await ConnectionMultiplexer.ConnectAsync(_options.ConfigurationOptions);
            else
                connection = await ConnectionMultiplexer.ConnectAsync(_options.Configuration);
        }
        else
        {
            connection = await _options.ConnectionMultiplexerFactory();
        }

        if (_options.ProfilingSession != null)
            connection.RegisterProfiler(_options.ProfilingSession);

        return connection;
    }

    /// 
    /// Create a new ConnectionMultiplexer instance
    /// 
    /// 
    protected virtual IConnectionMultiplexer Connect()
    {
        IConnectionMultiplexer connection;

        if (_options.ConnectionMultiplexerFactory is null)
            connection = _options.ConfigurationOptions is not null ? ConnectionMultiplexer.Connect(_options.ConfigurationOptions) : ConnectionMultiplexer.Connect(_options.Configuration);
        else
            connection = _options.ConnectionMultiplexerFactory().GetAwaiter().GetResult();

        if (_options.ProfilingSession != null)
            connection.RegisterProfiler(_options.ProfilingSession);

        return connection;
    }

    /// 
    /// Get connection to Redis servers, and reconnects if necessary
    /// 
    /// 
    protected virtual async Task GetConnectionAsync()
    {
        if (_connection?.IsConnected == true)
            return _connection;

        await _connectionLock.WaitAsync();
        try
        {
            if (_connection?.IsConnected == true)
                return _connection;

            //Connection disconnected. Disposing connection...
            _connection?.Dispose();

            //Creating new instance of Redis Connection
            _connection = await ConnectAsync();
        }
        finally
        {
            _connectionLock.Release();
        }

        return _connection;
    }

    /// 
    /// Get connection to Redis servers, and reconnects if necessary
    /// 
    /// 
    protected virtual IConnectionMultiplexer GetConnection()
    {
        if (_connection?.IsConnected == true)
            return _connection;

        _connectionLock.Wait();
        try
        {
            if (_connection?.IsConnected == true)
                return _connection;

            //Connection disconnected. Disposing connection...
            _connection?.Dispose();

            //Creating new instance of Redis Connection
            _connection = Connect();
        }
        finally
        {
            _connectionLock.Release();
        }

        return _connection;
    }

    #endregion

    #region Methods

    /// 
    /// Obtain an interactive connection to a database inside Redis
    /// 
    /// Redis cache database
    public async Task GetDatabaseAsync()
    {
        return (await GetConnectionAsync()).GetDatabase();
    }

    /// 
    /// Obtain an interactive connection to a database inside Redis
    /// 
    /// Redis cache database
    public IDatabase GetDatabase()
    {
        return GetConnection().GetDatabase();
    }

    /// 
    /// Obtain a configuration API for an individual server
    /// 
    /// The network endpoint
    /// Redis server
    public async Task GetServerAsync(EndPoint endPoint)
    {
        return (await GetConnectionAsync()).GetServer(endPoint);
    }

    /// 
    /// Gets all endpoints defined on the server
    /// 
    /// Array of endpoints
    public async Task GetEndPointsAsync()
    {
        return (await GetConnectionAsync()).GetEndPoints();
    }

    /// 
    /// Gets a subscriber for the server
    /// 
    /// Array of endpoints
    public async Task GetSubscriberAsync()
    {
        return (await GetConnectionAsync()).GetSubscriber();
    }

    /// 
    /// Gets a subscriber for the server
    /// 
    /// Array of endpoints
    public ISubscriber GetSubscriber()
    {
        return GetConnection().GetSubscriber();
    }

    /// 
    /// Delete all the keys of the database
    /// 
    public async Task FlushDatabaseAsync()
    {
        var endPoints = await GetEndPointsAsync();
        await Task.WhenAll(endPoints.Select(async endPoint =>
        {
            var server = await GetServerAsync(endPoint);
            if (!server.IsReplica)
            {
                await server.FlushDatabaseAsync();
            }
        }));
    }

    /// 
    /// Release all resources associated with this object
    /// 
    public void Dispose()
    {
        //dispose ConnectionMultiplexer
        _connection?.Dispose();
    }

    #endregion

    #region Properties

    /// 
    /// The Redis instance name
    /// 
    public string Instance => _options.InstanceName ?? string.Empty;

    #endregion
}