Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exception of type 'System.OutOfMemoryException' was thrown. at StackExchange.Redis.ConnectionMultiplexer.add_ConnectionRestored #1201

Closed
hgmauri opened this issue Aug 1, 2019 · 3 comments

Comments

@hgmauri
Copy link

hgmauri commented Aug 1, 2019

Hello

I have an "OutOfMemoryException" error using .NET CORE 2.2.

The full description of the error is:

System.OutOfMemoryException:
   at System.MulticastDelegate.CombineImpl (System.Private.CoreLib, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = 7cec85d7bea7798e)
   at StackExchange.Redis.ConnectionMultiplexer.add_ConnectionRestored (StackExchange.Redis, Version = 2.0.0.0, Culture = neutral, PublicKeyToken = c219ff1ca8c2ce46)
   at V1.Sdk.Infra.Repository.RedisRepository.RegisterEvent (V1.Sdk.Infra, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null)
   at V1.Sdk.Infra.Repository.RedisRepository.get_ConnectionMultiplexer (V1.Sdk.Infra, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null)
   at V1.Sdk.Infra.Repository.RedisRepository.GetDatabase (V1.Sdk.Infra, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null)
   at Vix.V1.Application.Services.Motorista.MotoristaService + d__17.MoveNext (Vix.V1.Application, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = nullVix.V1.Application, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null: d: \ a \ 1 \ s \ Vix.V1.Application \ Services \ Driver \ DriverService.ObterLogado.csVix.V1.Application, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null: 31)
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw (System.Private.CoreLib, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = 7cec85d7bea7798e)
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Private.CoreLib, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = 7cec85d7bea7798e)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Private.CoreLib, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = 7cec85d7bea7798e)
   at Vix.V1.Application.Services.Location.LocationService + d__2.MoveNext (Vix.V1.Application, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = nullVix.V1.Application, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null: d: \ a \ 1 \ s \ Vix.V1.Application \ Services \ Location \ LocationService.UpdatePosition.csVix.V1.Application, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null: 27)

The class you use to access redis is:

public class RedisRepository
    {
        private static readonly object Locker = new object ();
        private static IConnectionMultiplexer _connMultiplexer;

        private static IConnectionMultiplexer ConnectionMultiplexer
        {
            get
            {
                if (_connMultiplexer == null ||! _connMultiplexer.IsConnected)
                {
                    lock (Locker)
                    {
                        if (_connMultiplexer == null ||! _connMultiplexer.IsConnected)
                        {
                            _connMultiplexer = Connection;
                        }
                    }
                }

                RegisterEvent ();

                return _connMultiplexer;
            }
        }

        private static readonly Lazy <ConnectionMultiplexer> LazyConnection = new Lazy <ConnectionMultiplexer> (() =>
        {
            var connection = StackExchange.Redis.ConnectionMultiplexer.Connect (AppContextSdk.Configuration.GetConnectionString ("RedisConnection"));

            return connection;
        });

        private static ConnectionMultiplexer Connection => LazyConnection.Value;

        public static IDatabase GetDatabase ()
        {
            return ConnectionMultiplexer.GetDatabase (0);
        }

        private static void RegisterEvent ()
        {
            _connMultiplexer.ConnectionRestored + = ConnMultiplexer_ConnectionRestored;
            _connMultiplexer.ConnectionFailed + = ConnMultiplexer_ConnectionFailed;
            _connMultiplexer.ErrorMessage + = ConnMultiplexer_ErrorMessage;
            _connMultiplexer.InternalError + = ConnMultiplexer_InternalError;
        }

        private static void ConnMultiplexer_ConnectionRestored (object sender, ConnectionFailedEventArgs and)
        {

        }

        private static void ConnMultiplexer_ConnectionFailed (object sender, ConnectionFailedEventArgs and)
        {

        }

        private static void ConnMultiplexer_ErrorMessage (object sender, RedisErrorEventArgs e)
        {
        }

        private static void ConnMultiplexer_InternalError (object sender, InternalErrorEventArgs e)
        {
        }
    }

The Redis used is Azure Redis Cache Premium 6GB.

Any idea what it might be or what you should do to solve it? Until then the solution is to restart App Service

@mgravell
Copy link
Collaborator

mgravell commented Aug 2, 2019

The problem is your ConnectionMultiplexer property. Every single time it is accessed, it adds additional event registrations. Eventually, this will explode. Before then, it is just a really bad idea. So... don't do that?

@hgmauri
Copy link
Author

hgmauri commented Aug 2, 2019

Perfect! It was exactly this point!
Thank you!

@EminemJK
Copy link

EminemJK commented Aug 5, 2019

ConnectionMultiplexer is thread-safe and does not require a lock,
` public static ConnectionMultiplexer Instance
{
get
{
return conn.Value;
}
}

    private static Lazy<ConnectionMultiplexer> conn = new Lazy<ConnectionMultiplexer>(
    () =>
    {
        _instance = ConnectionMultiplexer.Connect(RedisPath);
        //adds additional event registrations
        _instance.ConnectionFailed += MuxerConnectionFailed;
        _instance.ConnectionRestored += MuxerConnectionRestored;
        _instance.ErrorMessage += MuxerErrorMessage;
        _instance.HashSlotMoved += MuxerHashSlotMoved;
        _instance.InternalError += MuxerInternalError;
        return _instance;
    }
    );`

and you can try using my packaged tool to search 'Banana.Utility' in nuget.

@hgmauri hgmauri closed this as completed Aug 13, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants