In working to update our 2.7.x client to use ssl connections to the cluster, we encountered a null reference when calling GetDocumentFromReplicaAsync<T>
and GetFromReplicaAsync<T>
.
Exception occurs here in library code: couchbase-net-client/CallbackFactory.cs at 2.7.17 · couchbase/couchbase-net-client · GitHub - the link is to 2.7.17 version we’re using, but the issue still exists on the latest 2.7.24 version.
Seems like the EndPoint
is not mapped in SslConnection
: couchbase-net-client/SslConnection.cs at 22628a63c2323cd9affdba58b227371e373798a6 · couchbase/couchbase-net-client · GitHub, while it is mapped in MultiplexingConnection
: couchbase-net-client/MultiplexingConnection.cs at 22628a63c2323cd9affdba58b227371e373798a6 · couchbase/couchbase-net-client · GitHub
The only difference in our implementation is setting UseSsl = true
on the bucket definition. Is this something we can address in our configuration? Seems like a defect with the client.
@brihulse -
Can you provide a code snippet of the configuration?
-Jeff
Here’s how we configure, initialize and access the cluster/buckets. Let me know if you need any more details.
public class CouchbaseBucketFactory : ICouchbaseBucketFactory
{
private static readonly Dictionary<CouchbaseBucketType, string> BucketMap = new Dictionary<CouchbaseBucketType, string>()
{
{ CouchbaseBucketType.Cache, "cache" },
{ CouchbaseBucketType.Storage, "storage" },
};
private static readonly ConcurrentDictionary<CouchbaseBucketType, Lazy<IBucket>> Buckets = new ConcurrentDictionary<CouchbaseBucketType, Lazy<IBucket>>();
public CouchbaseBucketFactory(ICouchbaseClientDefinitionProvider definitionProvider, IServerResolver serverResolver)
{
var definition = new CouchbaseClientDefinition
{
Servers = serverResolver.GetServers().ToList(),
Buckets = definitionProvider.GetBuckets().Select(GetBucketDefinition).ToList(),
ForceSaslPlain = definitionProvider.GetForceSaslPlain()
};
var clusterConfiguration = new ClientConfiguration(definition);
var serializationSettings = new JsonSerializerSettings()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
TypeNameHandling = TypeNameHandling.All
};
clusterConfiguration.Transcoder = () => new DefaultTranscoder(new DefaultConverter(), new DefaultSerializer(serializationSettings, serializationSettings));
clusterConfiguration.Serializer = () => new DefaultSerializer(serializationSettings, serializationSettings);
ClusterHelper.Initialize(clusterConfiguration);
}
private static BucketDefinition GetBucketDefinition(BucketConfigData bucket)
{
var connectionPool = new ConnectionPoolDefinition
{
MaxSize = bucket.ConnectionPool.MaxSize,
MinSize = bucket.ConnectionPool.MinSize,
};
if (bucket.ConnectionPool.WaitTimeout.HasValue)
{
connectionPool.WaitTimeout = bucket.ConnectionPool.WaitTimeout.Value;
}
if (bucket.ConnectionPool.ShutdownTimeout.HasValue)
{
connectionPool.ShutdownTimeout = bucket.ConnectionPool.ShutdownTimeout.Value;
}
return new BucketDefinition
{
Name = bucket.Name,
Password = bucket.Password,
UseSsl = bucket.UseSsl,
ConnectionPool = connectionPool
};
}
public IBucket GetBucket(CouchbaseBucketType bucketType)
{
return Buckets.GetOrAdd(bucketType, PrivateGetBucket).Value;
}
private static Lazy<IBucket> PrivateGetBucket(CouchbaseBucketType bucketType)
{
var bucketName = BucketMap[bucketType];
return new Lazy<IBucket>(() => ClusterHelper.Get().OpenBucket(bucketName), LazyThreadSafetyMode.ExecutionAndPublication);
}
}
@jmorris One important note that we found with additional testing today. We only see this null reference error when attempting to get a document from replica that does not exist.
I went back through and reviewed the documentation and the example here is showing it goes to replica on ResponseStatus.KeyNotFound
status. Is this example misleading or would we see a ResponseStatus.KeyNotFound
if the active node is unavailable?
@brihulse -
Thanks for the update. Do you have a stacktrace of the exception you can post?
Jeff
```
System.NullReferenceException: Object reference not set to an instance of an object.
at Couchbase.Core.Buckets.CallbackFactory.CreateOperationContext(SocketAsyncState state, Nullable`1 serverDuration, String bucketName)
at Couchbase.Core.Buckets.CallbackFactory.<>c__DisplayClass7_0`1.<<CompletedFuncForRetry>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Couchbase.Core.Server.SendAsync[T](IOperation`1 operation)
at Couchbase.Core.Buckets.RequestExecuterBase.ReadFromReplicaAsync[T](ReplicaRead`1 operation)
at Couchbase.CouchbaseBucket.GetDocumentFromReplicaAsync[T](String id, TimeSpan timeout)
at Couchbase.CouchbaseBucket.GetDocumentFromReplicaAsync[T](String id, TimeSpan timeout)
```
@brihulse -
I created a ticket and patch for a fix based on what I see here. Feel free to create an account on review.couchbase.com and try it out.
Thanks,
Jeff
That’s great thanks! We’ve given it a shot and it works in our tests. Any idea on the timeline of when this would be officially released?
@brihulse
Good to hear, should be available the first week of June in v2.7.26
Jeff