Redis Connections May Not be Closing with c#
Asked Answered
M

2

6

I'm connecting to Azure Redis and they show me the number of open connections to my redis server. I've got the following c# code that encloses all my Redis sets and gets. Should this be leaking connections?

       using (var connectionMultiplexer = ConnectionMultiplexer.Connect(connectionString))
        {

            lock (Locker)
            {
                redis = connectionMultiplexer.GetDatabase();
            }

            var o = CacheSerializer.Deserialize<T>(redis.StringGet(cacheKeyName));
            if (o != null)
            {
                return o;
            }
            lock (Locker)
            {
                // get lock but release if it takes more than 60 seconds to complete to avoid deadlock if this app crashes before release
                //using (redis.AcquireLock(cacheKeyName + "-lock", TimeSpan.FromSeconds(60)))

                var lockKey = cacheKeyName + "-lock";
                if (redis.LockTake(lockKey, Environment.MachineName, TimeSpan.FromSeconds(10)))
                {
                    try
                    {
                        o = CacheSerializer.Deserialize<T>(redis.StringGet(cacheKeyName));
                        if (o == null)
                        {
                            o = func();
                            redis.StringSet(cacheKeyName, CacheSerializer.Serialize(o),
                                TimeSpan.FromSeconds(cacheTimeOutSeconds));
                        }
                        redis.LockRelease(lockKey, Environment.MachineName);
                        return o;
                    }
                    finally
                    {
                        redis.LockRelease(lockKey, Environment.MachineName);
                    }
                }
                return o;
            }

        }
    }
Manlove answered 25/2, 2016 at 2:21 Comment(0)
N
5

You can keep connectionMultiplexer in a static variable and not create it for every get/set. That will keep one connection to Redis always opening and proceed your operations faster.

Update: Please, have a look at StackExchange.Redis basic usage: https://github.com/StackExchange/StackExchange.Redis/blob/master/Docs/Basics.md

"Note that ConnectionMultiplexer implements IDisposable and can be disposed when no longer required, but I am deliberately not showing using statement usage, because it is exceptionally rare that you would want to use a ConnectionMultiplexer briefly, as the idea is to re-use this object."

It works nice for me, keeping single connection to Azure Redis (sometimes, create 2 connections, but this by design). Hope it will help you.

Northeastwards answered 26/2, 2016 at 8:50 Comment(3)
That is what I had originally and my monitor showed 100s of open connections when I was Only one testingManlove
Thanks. I'll read that and update my method and see if I can get it to work.Manlove
This link now gives a 404 - I believe the page has moved here: stackexchange.github.io/StackExchange.Redis/BasicsTerzetto
P
0

I was suggesting try using Close (or CloseAsync) method explicitly. In a test setting you may be using different connections for different test cases and not want to share a single multiplexer. A search for public code using Redis client shows a pattern of Close followed by Dispose calls.

Noting in the XML method documentation of Redis client that close method is described as doing more:

    //
    // Summary:
    //     Close all connections and release all resources associated with this object
    //
    // Parameters:
    //   allowCommandsToComplete:
    //     Whether to allow all in-queue commands to complete first.
    public void Close(bool allowCommandsToComplete = true);
    //
    // Summary:
    //     Close all connections and release all resources associated with this object
    //
    // Parameters:
    //   allowCommandsToComplete:
    //     Whether to allow all in-queue commands to complete first.
    [AsyncStateMachine(typeof(<CloseAsync>d__183))]
    public Task CloseAsync(bool allowCommandsToComplete = true);

...

//
// Summary:
//     Release all resources associated with this object
public void Dispose();

And then I looked up the code for the client, found it here:

https://github.com/StackExchange/StackExchange.Redis/blob/master/src/StackExchange.Redis/ConnectionMultiplexer.cs

And we can see Dispose method calling Close (not the usual override-able protected Dispose(bool)), further more with the wait for connections to close set to true. It appears to be an atypical dispose pattern implementation in that by trying all the closure and waiting on them it is chancing to run into exception while Dispose method contract is supposed to never throw one.

Pattani answered 18/12, 2019 at 0:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.