Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does ConnectionMultiplexer deal with disconnects?

Tags:

The Basic Usage documentation for StackExchange.Redis explains that the ConnectionMultiplexer is long-lived and is expected to be reused.

But what about when the connection to the server is broken? Does ConnectionMultiplexer automatically reconnect, or is it necessary to write code as in this answer (quoting that answer):

        if (RedisConnection == null || !RedisConnection.IsConnected)
        {
            RedisConnection = ConnectionMultiplexer.Connect(...);
        }
        RedisCacheDb = RedisConnection.GetDatabase();

Is the above code something good to handle recovery from disconnects, or would it actually result in multiple ConnectionMultiplexer instances? Along the same lines, how should the IsConnected property be interpreted?

[Aside: I believe the above code is a pretty bad form of lazy initialization, particularly in multithreaded environments - see Jon Skeet's article on Singletons].

like image 834
Gigi Avatar asked Mar 01 '15 09:03

Gigi


People also ask

How do I set false abortConnect?

Setting AbortOnConnectFail to false will tell StackExchange. Redis to automatically reconnect in the background when the connection is lost for any reason. Example using a Connection String: var connectionString = "mycache.redis.cache.windows.net,abortConnect=false, ssl=true,password=..."

What is Redis ConnectionMultiplexer?

Redis is the ConnectionMultiplexer class in the StackExchange. Redis namespace; this is the object that hides away the details of multiple servers. Because the ConnectionMultiplexer does a lot, it is designed to be shared and reused between callers. You should not create a ConnectionMultiplexer per operation.


2 Answers

Here is the pattern recommended by the Azure Redis Cache team:

private static Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() => {
    return ConnectionMultiplexer.Connect("mycache.redis.cache.windows.net,abortConnect=false,ssl=true,password=...");
});

public static ConnectionMultiplexer Connection {
    get {
        return lazyConnection.Value;
    }
}

A few important points:

  • It uses Lazy<T> to handle thread-safe initialization
  • It sets "abortConnect=false", which means if the initial connect attempt fails, the ConnectionMultiplexer will silently retry in the background rather than throw an exception.
  • It does not check the IsConnected property, since ConnectionMultiplexer will automatically retry in the background if the connection is dropped.
like image 144
Mike Harder Avatar answered Sep 20 '22 11:09

Mike Harder


Yes, you need that type of verification in order to fix broken connections. Some thread safety should also be factored in as well. This is how I usually do this:

private static ConnectionMultiplexer _redis;
private static readonly Object _multiplexerLock = new Object();

private void ConnectRedis()
{
    try
    {
        _redis = ConnectionMultiplexer.Connect("...<connection string here>...");
    }
    catch (Exception ex)
    {
        //exception handling goes here
    }
}


private ConnectionMultiplexer RedisMultiplexer
{
    get
    {
        lock (_multiplexerLock)
        {
            if (_redis == null || !_redis.IsConnected)
            {
                ConnectRedis();
            }
            return _redis;
        }
    }
}

Then I use the RedisMultiplexer property everywhere I need to call the Redis endpoint. I don't usually store the result of the GetDatabase() call because the documentation says it's a pretty lightweight call.

like image 41
CyberDude Avatar answered Sep 20 '22 11:09

CyberDude