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

Use LazyThreadSafetyMode.PublicationOnly to avoid caching exception when creating rabbitmq connection #8998

Closed
RayMMond opened this issue May 12, 2021 · 3 comments
Assignees
Milestone

Comments

@RayMMond
Copy link
Contributor

RayMMond commented May 12, 2021

Problem

return Connections.GetOrAdd(
connectionName, () => new Lazy<IConnection>(() =>
{
var connection = Options.Connections.GetOrDefault(connectionName);
var hostnames = connection.HostName.TrimEnd(';').Split(';');
// Handle Rabbit MQ Cluster.
return hostnames.Length == 1 ? connection.CreateConnection() : connection.CreateConnection(hostnames);
})
).Value;

If connection factory failed and throw a exception (timeout...), Lazy<IConnection> will cache exception and rethrow it everytime when you access it's Value Property.

Solution

According to this link:

In PublicationOnly thread safety mode, multiple threads can invoke the initialization logic but the first thread to complete the initialization successfully sets the value of the Lazy instance.

Maybe we should add LazyThreadSafetyMode.PublicationOnly to Lazy<T>'s ctor ?

 return Connections.GetOrAdd( 
     connectionName, () => new Lazy<IConnection>(() => 
     { 
         var connection = Options.Connections.GetOrDefault(connectionName); 
         var hostnames = connection.HostName.TrimEnd(';').Split(';'); 
         // Handle Rabbit MQ Cluster. 
         return hostnames.Length == 1 ? connection.CreateConnection() : connection.CreateConnection(hostnames); 
  
     }, LazyThreadSafetyMode.PublicationOnly) 
 ).Value; 
@maliming maliming added this to the 4.3-patch milestone May 12, 2021
@RayMMond
Copy link
Contributor Author

And this is another approach:

            connectionName ??= RabbitMqConnections.DefaultConnectionName;

            var lazyConnection = Connections.GetOrAdd(connectionName, () =>
                new Lazy<IConnection>(() =>
                {
                    var connection = Options.Connections.GetOrDefault(connectionName);
                    var hostnames = connection.HostName.TrimEnd(';').Split(';');
                    // Handle Rabbit MQ Cluster.
                    return hostnames.Length == 1
                        ? connection.CreateConnection()
                        : connection.CreateConnection(hostnames);
                }));

            if (!lazyConnection.IsValueCreated)
            {
                Connections.TryRemove(connectionName, out _);
            }

            return lazyConnection.Value;

@realLiangshiwei
Copy link
Member

realLiangshiwei commented May 13, 2021

We can't use LazyThreadSafetyMode.PublicationOnly, because it allows all threads to execute valueFactory, It will open a lot of connections.

I will try find a better way.

@realLiangshiwei
Copy link
Member

realLiangshiwei commented May 13, 2021

And this is another approach:

            connectionName ??= RabbitMqConnections.DefaultConnectionName;

            var lazyConnection = Connections.GetOrAdd(connectionName, () =>
                new Lazy<IConnection>(() =>
                {
                    var connection = Options.Connections.GetOrDefault(connectionName);
                    var hostnames = connection.HostName.TrimEnd(';').Split(';');
                    // Handle Rabbit MQ Cluster.
                    return hostnames.Length == 1
                        ? connection.CreateConnection()
                        : connection.CreateConnection(hostnames);
                }));

            if (!lazyConnection.IsValueCreated)
            {
                Connections.TryRemove(connectionName, out _);
            }

            return lazyConnection.Value;

This way has a problem, Valuefactory will be executed directly only when calling lazyConnection.Value;, IsValueCreated is always false.
`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants