-
Notifications
You must be signed in to change notification settings - Fork 48
Description
Symptoms
The following error appears in the ServiceControl log:
Particular.LicensingComponent.BrokerThroughput.BrokerThroughputCollectorHostedService|Failed to gather throughput from broker|System.Text.Json.JsonException: Unknown queue type: rabbit_mqtt_qos0_queue
Who's affected
Anyone generating a usage report in ServiceControl with a RabbitMQ server that has the MQTT Plugin enabled and uses MQTT QoS 0 queues.
Root cause
- The MQTT QoS 0 queue type was not handled correctly by the RabbitMQ transport's queue type converter.
Confirmed workarounds
- None
Original bug report
Describe the bug
Description
ServiceControl usage tool throws an exception when scanning the queues with mqtt qos0 queue types. The error is thrown by the transport queue type converter.
Expected behavior
Usage tool skips those queue types and does not fail.
Actual behavior
An exception is thrown and the usage functionality does not complete.
Versions
Please list the version of the relevant packages or applications in which the bug exists.
- ServiceControl 6.7.1, most likely in all versions that support collecting usage data.
Steps to reproduce
- Create a queue in the RabbitMQ broker that uses an unsupported queue type.
- Run the usage tool in ServiceControl
- Check log files for the exception above.
Relevant log output
2025-08-06 13:41:25.5385|00:01:09.798|56|Error|Particular.LicensingComponent.BrokerThroughput.BrokerThroughputCollectorHostedService|Failed to gather throughput from broker|System.Text.Json.JsonException: Unknown queue type: rabbit_mqtt_qos0_queue
at NServiceBus.Transport.RabbitMQ.ManagementApi.QueueTypeConverter.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options) in /_/src/NServiceBus.Transport.RabbitMQ/Administration/ManagementApi/Converters/QueueTypeConverter.cs:line 20
at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
at System.Text.Json.Serialization.JsonCollectionConverter`2.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, TCollection& value)
at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value, Boolean& isPopulatedValue)
at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.DeserializeAsync(Stream utf8Json, CancellationToken cancellationToken)
at System.Net.Http.Json.HttpClientJsonExtensions.<FromJsonAsyncCore>g__Core|12_0[TValue,TJsonOptions](HttpClient client, Task`1 responseTask, Boolean usingResponseHeadersRead, CancellationTokenSource linkedCTS, Func`4 deserializeMethod, TJsonOptions jsonOptions, CancellationToken cancellationToken)
at NServiceBus.Transport.RabbitMQ.ManagementApi.ManagementClient.Get[T](String url, CancellationToken cancellationToken)
at NServiceBus.Transport.RabbitMQ.ManagementApi.ManagementClient.GetQueues(Int32 page, Int32 pageSize, CancellationToken cancellationToken) in /_/src/NServiceBus.Transport.RabbitMQ/Administration/ManagementApi/ManagementClient.cs:line 127
at ServiceControl.Transports.RabbitMQ.RabbitMQQuery.<>c__DisplayClass5_0.<<GetQueueNames>b__0>d.MoveNext() in /_/src/ServiceControl.Transports.RabbitMQ/RabbitMQQuery.cs:line 78
--- End of stack trace from previous location ---
at Polly.ResiliencePipeline.<>c__10`1.<<ExecuteAsync>b__10_0>d.MoveNext()
--- End of stack trace from previous location ---
at Polly.Outcome`1.GetResultOrRethrow()
at Polly.ResiliencePipeline.ExecuteAsync[TResult](Func`2 callback, CancellationToken cancellationToken)
at ServiceControl.Transports.RabbitMQ.RabbitMQQuery.GetQueueNames(CancellationToken cancellationToken)+MoveNext() in /_/src/ServiceControl.Transports.RabbitMQ/RabbitMQQuery.cs:line 78
at ServiceControl.Transports.RabbitMQ.RabbitMQQuery.GetQueueNames(CancellationToken cancellationToken)+System.Threading.Tasks.Sources.IValueTaskSource<System.Boolean>.GetResult()
at Particular.LicensingComponent.BrokerThroughput.BrokerThroughputCollectorHostedService.GatherThroughput(CancellationToken stoppingToken) in /_/src/Particular.LicensingComponent/BrokerThroughput/BrokerThroughputCollectorHostedService.cs:line 69
at Particular.LicensingComponent.BrokerThroughput.BrokerThroughputCollectorHostedService.GatherThroughput(CancellationToken stoppingToken) in /_/src/Particular.LicensingComponent/BrokerThroughput/BrokerThroughputCollectorHostedService.cs:line 69
at Particular.LicensingComponent.BrokerThroughput.BrokerThroughputCollectorHostedService.ExecuteAsync(CancellationToken stoppingToken) in /_/src/Particular.LicensingComponent/BrokerThroughput/BrokerThroughputCollectorHostedService.cs:line 48Additional Information
Workarounds
- Use the legacy throughput usage tool instead.
Possible solutions
Update the queue type parser to handle all RabbitMQ queue types gracefully.
Additional information
The QueueTypeConverter System.Text.Json converter throws an exception if a queue type that is not hard coded in the switch statement is indicated in the JSON.
This converter is triggered during the ManagementClient.GetQueues method call when deserializing the response:
The ServiceControl.Transport.RabbitMQ library calls the ManagementClient.GetQueues method:
[!NOTE]
TheManagementClientclass is accessed via internals visible to by theServiceControl.Transport.RabbitMQlibrary.