|
4 | 4 | using System.Collections.Concurrent; |
5 | 5 | using System.Threading; |
6 | 6 | using System.Threading.Tasks; |
7 | | - using global::RabbitMQ.Client; |
8 | 7 | using NServiceBus.Logging; |
9 | | - using NServiceBus.Transport.RabbitMQ; |
10 | | - using ConnectionFactory = NServiceBus.Transport.RabbitMQ.ConnectionFactory; |
| 8 | + using NServiceBus.Transport.RabbitMQ.ManagementApi; |
11 | 9 |
|
12 | 10 | class QueueLengthProvider : AbstractQueueLengthProvider |
13 | 11 | { |
14 | | - public QueueLengthProvider(TransportSettings settings, Action<QueueLengthEntry[], EndpointToQueueMapping> store) : base(settings, store) |
| 12 | + public QueueLengthProvider(TransportSettings settings, Action<QueueLengthEntry[], EndpointToQueueMapping> store, ITransportCustomization transportCustomization) : base(settings, store) |
15 | 13 | { |
16 | | - queryExecutor = new QueryExecutor(ConnectionString); |
17 | | - queryExecutor.Initialize(); |
| 14 | + if (transportCustomization is IManagementClientProvider provider) |
| 15 | + { |
| 16 | + managementClient = provider.ManagementClient; |
| 17 | + } |
| 18 | + else |
| 19 | + { |
| 20 | + throw new ArgumentException($"Transport customization does not implement {nameof(IManagementClientProvider)}. Type: {transportCustomization.GetType().Name}", nameof(transportCustomization)); |
| 21 | + } |
18 | 22 | } |
19 | 23 |
|
20 | 24 | public override void TrackEndpointInputQueue(EndpointToQueueMapping queueToTrack) => |
@@ -76,90 +80,37 @@ async Task FetchQueueLengths(CancellationToken cancellationToken) |
76 | 80 | { |
77 | 81 | foreach (var endpointQueuePair in endpointQueues) |
78 | 82 | { |
79 | | - await queryExecutor.Execute(async m => |
80 | | - { |
81 | | - var queueName = endpointQueuePair.Value; |
82 | | - |
83 | | - try |
84 | | - { |
85 | | - var size = (int)await m.MessageCountAsync(queueName, cancellationToken).ConfigureAwait(false); |
86 | | - |
87 | | - sizes.AddOrUpdate(queueName, _ => size, (_, __) => size); |
88 | | - } |
89 | | - catch (Exception e) |
90 | | - { |
91 | | - Logger.Warn($"Error querying queue length for {queueName}", e); |
92 | | - } |
93 | | - }, cancellationToken); |
94 | | - } |
95 | | - } |
96 | | - |
97 | | - readonly QueryExecutor queryExecutor; |
98 | | - static readonly TimeSpan QueryDelayInterval = TimeSpan.FromMilliseconds(200); |
99 | | - |
100 | | - readonly ConcurrentDictionary<string, string> endpointQueues = new ConcurrentDictionary<string, string>(); |
101 | | - readonly ConcurrentDictionary<string, int> sizes = new ConcurrentDictionary<string, int>(); |
102 | | - |
103 | | - static readonly ILog Logger = LogManager.GetLogger<QueueLengthProvider>(); |
104 | | - |
105 | | - class QueryExecutor(string connectionString) : IDisposable |
106 | | - { |
107 | | - |
108 | | - public void Initialize() |
109 | | - { |
110 | | - var connectionConfiguration = ConnectionConfiguration.Create(connectionString); |
111 | | - |
112 | | - // TODO Fix this up |
113 | | - //var dbConnectionStringBuilder = new DbConnectionStringBuilder { ConnectionString = connectionString }; |
114 | | - |
115 | | - connectionFactory = new("ServiceControl.Monitoring", |
116 | | - connectionConfiguration, |
117 | | - null, //providing certificates is not supported yet |
118 | | - false, // TODO Fix dbConnectionStringBuilder.GetBooleanValue("DisableRemoteCertificateValidation"), |
119 | | - false, // TODO fix dbConnectionStringBuilder.GetBooleanValue("UseExternalAuthMechanism"), |
120 | | - TimeSpan.FromSeconds(60), // value would come from config API in actual transport |
121 | | - TimeSpan.FromSeconds(10), // value would come from config API in actual transport |
122 | | - null); // value would come from config API in actual transport |
123 | | - } |
| 83 | + var queueName = endpointQueuePair.Value; |
124 | 84 |
|
125 | | - public async Task Execute(Action<IChannel> action, CancellationToken cancellationToken = default) |
126 | | - { |
127 | 85 | try |
128 | 86 | { |
129 | | - connection ??= await connectionFactory.CreateConnection("queue length monitor", cancellationToken: cancellationToken); |
| 87 | + var (statusCode, reason, queue) = await managementClient.GetQueue(queueName, cancellationToken); |
130 | 88 |
|
131 | | - //Connection implements reconnection logic |
132 | | - while (!connection.IsOpen) |
| 89 | + if (queue is not null) |
133 | 90 | { |
134 | | - await Task.Delay(ReconnectionDelay, cancellationToken); |
| 91 | + var size = queue.MessageCount; |
| 92 | + sizes.AddOrUpdate(queueName, _ => size, (_, _) => size); |
135 | 93 | } |
136 | | - |
137 | | - if (channel == null || channel.IsClosed) |
| 94 | + else |
138 | 95 | { |
139 | | - channel?.Dispose(); |
140 | | - |
141 | | - channel = await connection.CreateChannelAsync(cancellationToken: cancellationToken).ConfigureAwait(false); |
| 96 | + Logger.Warn($"Error querying queue length for {queueName}. {statusCode}: {reason}"); |
142 | 97 | } |
143 | 98 |
|
144 | | - action(channel); |
145 | | - } |
146 | | - catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) |
147 | | - { |
148 | | - // no-op |
149 | 99 | } |
150 | 100 | catch (Exception e) |
151 | 101 | { |
152 | | - Logger.Warn("Error querying queue length.", e); |
| 102 | + Logger.Warn($"Error querying queue length for {queueName}", e); |
153 | 103 | } |
154 | 104 | } |
| 105 | + } |
155 | 106 |
|
156 | | - public void Dispose() => connection?.Dispose(); |
| 107 | + static readonly TimeSpan QueryDelayInterval = TimeSpan.FromMilliseconds(200); |
157 | 108 |
|
158 | | - IConnection connection; |
159 | | - IChannel channel; |
160 | | - ConnectionFactory connectionFactory; |
| 109 | + readonly ConcurrentDictionary<string, string> endpointQueues = new(); |
| 110 | + readonly ConcurrentDictionary<string, long> sizes = new(); |
161 | 111 |
|
162 | | - static readonly TimeSpan ReconnectionDelay = TimeSpan.FromSeconds(5); |
163 | | - } |
| 112 | + static readonly ILog Logger = LogManager.GetLogger<QueueLengthProvider>(); |
| 113 | + |
| 114 | + readonly ManagementClient managementClient; |
164 | 115 | } |
165 | 116 | } |
0 commit comments