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

System.Uri error in Container.ReadThroughputAsync #728

Closed
Druid-of-Luhn opened this issue Aug 22, 2019 · 5 comments · Fixed by #772
Closed

System.Uri error in Container.ReadThroughputAsync #728

Druid-of-Luhn opened this issue Aug 22, 2019 · 5 comments · Fixed by #772
Assignees
Labels
bug Something isn't working needs-investigation

Comments

@Druid-of-Luhn
Copy link

Describe the bug
When calling Container.ReadThroughputAsync() on a non-null container that has a throughput value (400 in this case), CosmosOffers.ReadThroughputAsync fails due to a "Value cannot be null" error in the System.Uri constructor.

To Reproduce

Get a container and call ReadThroughputAsync() on it:

CosmosClient _cosmosClient = new CosmosClient(
    _configuration.Endpoint,
    _configuration.AuthKey,
    new CosmosClientOptions
    {
        ConnectionMode = _configuration.ConnectionMode,
        ConsistencyLevel = ConsistencyLevel.Session,
        GatewayModeMaxConnectionLimit = _configuration.MaxConnectionLimit,
        RequestTimeout = _configuration.RequestTimeout,
        MaxRetryAttemptsOnRateLimitedRequests = _configuration.MaxRetryAttemptsOnThrottledRequests,
        MaxRetryWaitTimeOnRateLimitedRequests = TimeSpan.FromSeconds(_configuration.MaxRetryWaitTimeInSeconds),
        Serializer = new CosmosJsonSerializer(_jsonSerializer), // Custom CosmosSerializer
    });
Database database = await _cosmosClient.CreateDatabaseIfNotExistsAsync(databaseId);
await database.CreateContainerIfNotExistsAsync(containerId, _configuration.PartitionKey, 400);
Container container = _cosmosClient.GetContainer(databaseId, containerId);
int? throughput = await container.ReadThroughputAsync();

Expected behavior

The method should return a value (in my case, I expect 400).

Actual behavior

A System.ArgumentNullException is thrown (see message and stack trace below).

Environment summary
SDK Version: 3.1.1
OS Version (e.g. Windows, Linux, MacOSX): Windows

Additional context

Exception message:

Value cannot be null.
Parameter name: uriString

Stack trace:

   at System.Uri..ctor(String uriString, UriKind uriKind)
   at Microsoft.Azure.Cosmos.CosmosOffers.<ReadThroughputAsync>d__3.MoveNext()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Azure.Cosmos.ContainerCore.<ReadThroughputAsync>d__24.MoveNext()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Azure.Cosmos.ContainerCore.<ReadThroughputAsync>d__23.MoveNext()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at AH.DS.Online.Common.Providers.CosmosDB.DocumentClientAdapter.<ElasticScaleCollectionThroughputAsync>d__21.MoveNext() in C:\Users\b_b\source\repos\ah-ds-online\src\ah-ds-online-common\Common.Providers.CosmosDB\DocumentClientAdapter.cs:line 197
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at AH.DS.Online.Publisher.Common.Services.ThroughputScaleService.<ScaleUpThroughputAsync>d__3.MoveNext() in C:\Users\b_b\source\repos\ah-ds-online\src\ah-ds-online-publisher\Publisher.Common\Services\ThroughputScaleService.cs:line 23
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at AH.DS.Online.Publisher.Common.Commands.MetadataProcessorCommand.<Execute>d__4.MoveNext() in C:\Users\b_b\source\repos\ah-ds-online\src\ah-ds-online-publisher\Publisher.Common\Commands\MetadataProcessorCommand.cs:line 36
@simplynaveen20
Copy link
Member

@Druid-of-Luhn Is this consistent issue with any container, or intermittent on specific container

@Druid-of-Luhn
Copy link
Author

@simplynaveen20 Consistent with all containers. Our process is:

  1. Create a new database (works)
  2. Create a new container with a partition key scheme of "/key" and a throughput of 400 (works)
  3. Read throughput on the container in order to increase it (fails - ignore exception and continue)
  4. Upsert multiple documents to the container (works)
  5. Read throughput on the container in order to decrease it (fails - ignore exception and continue)
  6. Execute stored procedure on the container (works)

Additional points that may be of interest:

  • Manually increasing or decreasing the throughput units works in the Azure portal.
  • We just upgraded from Cosmos SDK 2 to SDK 3.
  • We have a custom CosmosSerializer instance for Json (de)serialization.

@Druid-of-Luhn
Copy link
Author

We have tried a reduced test case in a Console App, and cannot replicate the issue: reading and replacing the throughput work as expected.

The main thing that was changed when updating to Cosmos SDK 3 was adding the custom CosmosSerializer (a wrapper around Newtonsfot.Json). Could that be the culprit?

public class CosmosJsonSerializer : CosmosSerializer
{
    private readonly IJsonSerializer _jsonSerializer;

    public CosmosJsonSerializer(IJsonSerializer jsonSerializer)
    {
        _jsonSerializer = jsonSerializer;
    }

    public override T FromStream<T>(Stream stream)
    {
        using (StreamReader reader = new StreamReader(stream))
        {
            return _jsonSerializer.DeserializeObject<T>(reader.ReadToEnd());
        }
    }

    public override Stream ToStream<T>(T input)
    {
        string serialized = _jsonSerializer.SerializeObject(input);
        // Do not close the stream (either the Stream or the StreamWriter),
        // as the returned stream should still be open
        Stream stream = new MemoryStream();
        StreamWriter writer = new StreamWriter(stream);
        writer.Write(serialized);
        writer.Flush();
        stream.Seek(0, SeekOrigin.Begin);
        return stream;
    }
}

@j82w
Copy link
Contributor

j82w commented Aug 23, 2019

@Druid-of-Luhn that is a possibility. Offers does do a query which might be using the custom serializer, but it should be using the property serializer. @simplynaveen20 can you verify this is the issue?

@simplynaveen20
Copy link
Member

Yea sound reasonable , custom serializer could play the role here. Will pick this item next week. Thanks for all the detail explanation of the issue , really appreciate that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working needs-investigation
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants