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

Diagnostics: Adds total number of active clients information #3037

Merged
merged 11 commits into from
Feb 28, 2022
39 changes: 33 additions & 6 deletions Microsoft.Azure.Cosmos/src/CosmosClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,11 @@ public class CosmosClient : IDisposable
private readonly string DatabaseRootUri = Paths.Databases_Root;
private ConsistencyLevel? accountConsistencyLevel;
private bool isDisposed = false;
private object disposedLock = new object();

internal static int numberOfClientsCreated;
internal static int NumberOfActiveClients;

internal DateTime? DisposedDateTimeUtc { get; private set; } = null;

static CosmosClient()
Expand Down Expand Up @@ -262,6 +265,7 @@ internal CosmosClient(
clientOptions ??= new CosmosClientOptions();

this.ClientId = this.IncrementNumberOfClientsCreated();

this.ClientContext = ClientContextCore.Create(
this,
clientOptions);
Expand Down Expand Up @@ -1232,9 +1236,27 @@ private Task InitializeContainersAsync(IReadOnlyList<(string databaseId, string

private int IncrementNumberOfClientsCreated()
{
this.IncrementNumberOfActiveClients();

return Interlocked.Increment(ref numberOfClientsCreated);
}

private int IncrementNumberOfActiveClients()
{
return Interlocked.Increment(ref NumberOfActiveClients);
}

private int DecrementNumberOfActiveClients()
{
// In case dispose is called multiple times. Check if at least 1 active client is there
if (NumberOfActiveClients > 0)
{
return Interlocked.Decrement(ref NumberOfActiveClients);
}

return 0;
}

private async Task InitializeContainerAsync(string databaseId, string containerId, CancellationToken cancellationToken = default)
{
ContainerInternal container = (ContainerInternal)this.GetContainer(databaseId, containerId);
Expand Down Expand Up @@ -1280,17 +1302,22 @@ public void Dispose()
/// <param name="disposing">True if disposing</param>
protected virtual void Dispose(bool disposing)
{
if (!this.isDisposed)
lock (this.disposedLock)
{
this.DisposedDateTimeUtc = DateTime.UtcNow;

if (disposing)
if (this.isDisposed == true)
{
this.ClientContext.Dispose();
return;
}

this.isDisposed = true;
}

this.DisposedDateTimeUtc = DateTime.UtcNow;

if (disposing)
{
this.ClientContext.Dispose();
ealsur marked this conversation as resolved.
Show resolved Hide resolved
this.DecrementNumberOfActiveClients();
sourabh1007 marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public ClientConfigurationTraceDatum(CosmosClientContext cosmosClientContext, Da
cosmosClientContext.ClientOptions.ApplicationPreferredRegions);

this.cachedNumberOfClientCreated = CosmosClient.numberOfClientsCreated;
this.cachedNumberOfActiveClient = CosmosClient.NumberOfActiveClients;
this.cachedUserAgentString = this.UserAgentContainer.UserAgent;
this.cachedSerializedJson = this.GetSerializedDatum();
}
Expand All @@ -46,9 +47,11 @@ public ReadOnlyMemory<byte> SerializedJson
{
get
{
if ((this.cachedUserAgentString != this.UserAgentContainer.UserAgent) ||
(this.cachedNumberOfClientCreated != CosmosClient.numberOfClientsCreated))
if (this.cachedUserAgentString != this.UserAgentContainer.UserAgent ||
this.cachedNumberOfClientCreated != CosmosClient.numberOfClientsCreated ||
this.cachedNumberOfActiveClient != CosmosClient.NumberOfActiveClients)
{
this.cachedNumberOfActiveClient = CosmosClient.NumberOfActiveClients;
this.cachedNumberOfClientCreated = CosmosClient.numberOfClientsCreated;
this.cachedUserAgentString = this.UserAgentContainer.UserAgent;
this.cachedSerializedJson = this.GetSerializedDatum();
Expand All @@ -62,6 +65,8 @@ public ReadOnlyMemory<byte> SerializedJson

private ReadOnlyMemory<byte> cachedSerializedJson;
private int cachedNumberOfClientCreated;
private int cachedNumberOfActiveClient;

private string cachedUserAgentString;

internal override void Accept(ITraceDatumVisitor traceDatumVisitor)
Expand All @@ -79,6 +84,8 @@ private ReadOnlyMemory<byte> GetSerializedDatum()

jsonTextWriter.WriteFieldName("NumberOfClientsCreated");
jsonTextWriter.WriteNumber64Value(this.cachedNumberOfClientCreated);
jsonTextWriter.WriteFieldName("NumberOfActiveClients");
sourabh1007 marked this conversation as resolved.
Show resolved Hide resolved
jsonTextWriter.WriteNumber64Value(this.cachedNumberOfActiveClient);
jsonTextWriter.WriteFieldName("User Agent");
jsonTextWriter.WriteStringValue(this.cachedUserAgentString);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,7 @@ public void Visit(ClientConfigurationTraceDatum clientConfigurationTraceDatum)
stringBuilder.AppendLine("Client Configuration");
stringBuilder.AppendLine($"Client Created Time: {clientConfigurationTraceDatum.ClientCreatedDateTimeUtc.ToString("o", CultureInfo.InvariantCulture)}");
stringBuilder.AppendLine($"Number Of Clients Created: {CosmosClient.numberOfClientsCreated}");
stringBuilder.AppendLine($"Number Of Active Clients: {CosmosClient.NumberOfActiveClients}");
stringBuilder.AppendLine($"User Agent: {clientConfigurationTraceDatum.UserAgentContainer.UserAgent}");
stringBuilder.AppendLine("Connection Config:");
stringBuilder.AppendLine($"{space}'gw': {clientConfigurationTraceDatum.GatewayConnectionConfig}");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------

namespace Microsoft.Azure.Cosmos.Tests
{
using System;
using System.Threading.Tasks;
using System.Xml.Serialization;
using VisualStudio.TestTools.UnitTesting;

[TestClass]
public class ActiveClientDiagnosticTest
{
private const string ConnectionString = "AccountEndpoint=https://localtestcosmos.documents.azure.com:443/;AccountKey=425Mcv8CXQqzRNCgFNjIhT424GK99CKJvASowTnq15Vt8LeahXTcN5wt3342vQ==;";

[TestInitialize]
public void Initialize()
{
CosmosClient.NumberOfActiveClients = 0;
}

[TestMethod]
public void SingleClientTest()
{
CosmosClient cosmosClient = new CosmosClient(ConnectionString);
Assert.AreEqual(1, CosmosClient.NumberOfActiveClients);
cosmosClient.Dispose();
}

[TestMethod]
public void MultiClientTest()
{
CosmosClient cosmosClient1 = new CosmosClient(ConnectionString); // Initializing 1st time
CosmosClient cosmosClient2 = new CosmosClient(ConnectionString); // Initializing 2nd time
Assert.AreEqual(2, CosmosClient.NumberOfActiveClients);
cosmosClient1.Dispose();
cosmosClient2.Dispose();
}

[TestMethod]
public void MultiClientWithDisposeTest()
{
CosmosClient cosmosClient1 = new CosmosClient(ConnectionString); // Initializing 1st time
CosmosClient cosmosClient2 = new CosmosClient(ConnectionString); // Initializing 2nd time
CosmosClient cosmosClient3 = new CosmosClient(ConnectionString); // Initializing 3rd time
cosmosClient2.Dispose(); // Destroying 1 instance
Assert.AreEqual(2, CosmosClient.NumberOfActiveClients);
cosmosClient1.Dispose();
cosmosClient3.Dispose();
}

[TestMethod]
public void MultiThreadClientDisposeTest()
{
CosmosClient cosmosClient1 = new CosmosClient(ConnectionString); // Initializing 1st time
CosmosClient cosmosClient2 = new CosmosClient(ConnectionString);

Parallel.Invoke(cosmosClient2.Dispose,
cosmosClient2.Dispose,
cosmosClient2.Dispose,
cosmosClient2.Dispose,
cosmosClient2.Dispose);

// Initializing 2nd time
Assert.AreEqual(1, CosmosClient.NumberOfActiveClients);
cosmosClient1.Dispose();
cosmosClient2.Dispose();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ public class DefaultTracingTests
[TestMethod]
public void DefaultTracingEnableTest()
{
// Access cosmos client to cause the static consturctor to get called
// Access cosmos client to cause the static constructor to get called
sourabh1007 marked this conversation as resolved.
Show resolved Hide resolved
Assert.IsTrue(CosmosClient.numberOfClientsCreated >= 0);
Assert.IsTrue(CosmosClient.NumberOfActiveClients >= 0);

if (!Debugger.IsAttached)
{
Expand Down