Describe the bug
In the scenario where Producer P is queuing messages into queue Q for consumption by a consumer C, when a monitoring client M periodically checks the queue, the ApproximateMessagesCount is only set the first time that GetPropertieAsync is called and never updated in subsequent calls..
Expected behavior
GetPropertiesAsync should update ApproximateMessageCount
Actual behavior (include Exception or Stack Trace)
ApproximateMessageCount is set on the first call but not on successive calls
To Reproduce
Create a monitoring client...
var queue = ... new QueueClient ...
while (true)
{
var props = await queue.GetPropertiesAsync().ConfigureAwait(false);
var count = props.Value?.ApproximateMessagesCount ??0;
Console.WriteLine($"current count is {count}");
await Task.Delay(TimeSpan.FromSeconds(5);
}
In this case, the count will be read correctly on the first iteration of the loop but will never subsequently change even though the external producer and consumer are running. (Variations in the message count can also be verified using Azure Storage Explorer)
The workaround is simply to include the QueueClient construction within the loop - it does not appear that there is any other way to force a update of the property set. The old Windows.Azure.Storage library had a RetrieveMessageCount method IIRC.
Environment:
12:12>dotnet --info
.NET SDK (reflecting any global.json):
Version: 5.0.100-rc.1.20452.10
Commit: 473d1b592eRuntime Environment:
OS Name: Windows
OS Version: 10.0.19041
OS Platform: Windows
RID: win10-x64
Base Path: C:\Program Files\dotnet\sdk\5.0.100-rc.1.20452.10\Host (useful for support):
Version: 5.0.0-rc.1.20451.14
Commit: 38017c3935.NET SDKs installed:
3.0.100-preview9-014004 [C:\Program Files\dotnet\sdk]
3.0.100 [C:\Program Files\dotnet\sdk]
3.1.100-preview3-014645 [C:\Program Files\dotnet\sdk]
3.1.100 [C:\Program Files\dotnet\sdk]
3.1.102 [C:\Program Files\dotnet\sdk]
3.1.201 [C:\Program Files\dotnet\sdk]
3.1.301 [C:\Program Files\dotnet\sdk]
5.0.100-rc.1.20452.10 [C:\Program Files\dotnet\sdk].NET runtimes installed:
Microsoft.AspNetCore.All 2.1.12 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.All 2.1.21 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.App 2.1.12 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 2.1.21 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 3.0.0-preview7.19365.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 3.0.0-preview9.19424.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 3.1.0-preview3.19555.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 3.1.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 3.1.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 3.1.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 3.1.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 3.1.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 5.0.0-rc.1.20451.17 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 2.1.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.1.21 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 3.0.0-preview7-27912-14 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 3.0.0-preview9-19423-09 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 3.1.0-preview3.19553.2 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 3.1.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 3.1.2 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 3.1.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 3.1.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 3.1.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 5.0.0-rc.1.20451.14 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 3.0.0-preview7-27912-14 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 3.0.0-preview9-19423-09 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 3.1.0-preview3.19553.2 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 3.1.0 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 3.1.2 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 3.1.3 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 3.1.5 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 3.1.7 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 5.0.0-rc.1.20452.2 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Thanks for the feedback! We are routing this to the appropriate team for follow-up. cc @xgithubtriage.
Thank you for your feedback. Tagging and routing to the team best able to assist.
Hi I was wondering what version of Azure.Storage.Queues are you using? (unless that's a typo and you meant the Queues package instead of the Blobs library)
Hi @amnguye - I'm using the latest stable.... "Azure.Storage.Queues" Version="12.4.2" Maybe you were referring to me mentioning "Windows.Azure.Storage" ? I actually meant "WindowsAzure.Storage" (no dot) That was the original (now deprecated) library for accessing all types of Azure resources and had an extra API for explicitly refreshing the message count.
@NeilMacMullen, the clients in v12 are stateless, I'm surprised moving the client constructor within the loop would make a difference.
If messages are constantly being created and consumed, it's going to be challenging to get the "correct" ApproximateMessagesCount, since it's going to be constantly changing. Why type of values are you seeing?
@seankane-msft
If messages are constantly being created and consumed, it's going to be challenging to get the "correct" ApproximateMessagesCount, since it's going to be constantly changing.
Of course - that's why the name is ApproximateMessageCount ! ;-) The point here is not to get the exact number, it is to check that the queue size is not continuously growing because the produce is outrunning the consumer.
Why type of values are you seeing
To expand a bit on this....
In this case, the count will be read correctly on the first iteration of the loop but will never subsequently change even though the external producer and consumer are running
Let's say there are (approximately) 50 messages in the queue. Then the code above will print out some number close to 50 and continue to print out the same number until restarted. When it's restarted, then the number will be "sampled* once again.
I'm surprised moving the client constructor within the loop would make a difference.
The observed behaviour is consistent with an implementation that...
Each call to QueueClient.GetProperties() calls the backend API, it does not short-circuit.
You need need to call GetProperties() each time you'd like an updated ApproximateMessageCount, the QueueProperties object will not update on its own.
You need need to call GetProperties() each time you'd like an updated ApproximateMessageCount
Yes, that's exactly what the code I posted in the bug report does. The point is that even after doing this the value of ApproximateMessageCount appears never to change (apart from the very first time the call is made).
Having said that, I'm now unable to reproduce this now so looking more like a bug at my end - apologies.
Great, glad you were able to get it resolved!