Skip to content

Commit ee20359

Browse files
committed
Close connections using HTTP API
Greatly simplify `RabbitMQCtl` class. Use `rabbitmq:management` docker image on Ubuntu
1 parent 17188c4 commit ee20359

File tree

5 files changed

+61
-58
lines changed

5 files changed

+61
-58
lines changed

.ci/ubuntu/gha-setup.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,13 @@ function start_rabbitmq
6363
--hostname "$rabbitmq_docker_name" \
6464
--publish 5671:5671 \
6565
--publish 5672:5672 \
66+
--publish 15672:15672 \
6667
--network "$docker_network_name" \
6768
--volume "$GITHUB_WORKSPACE/.ci/ubuntu/enabled_plugins:/etc/rabbitmq/enabled_plugins" \
6869
--volume "$GITHUB_WORKSPACE/.ci/ubuntu/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf:ro" \
6970
--volume "$GITHUB_WORKSPACE/.ci/certs:/etc/rabbitmq/certs:ro" \
7071
--volume "$GITHUB_WORKSPACE/.ci/ubuntu/log:/var/log/rabbitmq" \
71-
rabbitmq:latest
72+
rabbitmq:management
7273
}
7374

7475
function wait_rabbitmq

projects/Test/Common/Common.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
</ItemGroup>
2727

2828
<ItemGroup>
29+
<PackageReference Include="EasyNetQ.Management.Client" Version="2.0.0" />
2930
<PackageReference Include="xunit" Version="2.7.0" />
3031
<PackageReference Include="xunit.abstractions" Version="2.0.3" />
3132
</ItemGroup>

projects/Test/Common/RabbitMQCtl.cs

Lines changed: 0 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -32,54 +32,20 @@
3232
using System;
3333
using System.Diagnostics;
3434
using System.IO;
35-
using System.Text.RegularExpressions;
3635
using System.Threading.Tasks;
37-
using RabbitMQ.Client;
3836
using Xunit.Abstractions;
3937

4038
namespace Test
4139
{
4240
public class RabbitMQCtl
4341
{
44-
private static readonly char[] newLine = new char[] { '\n' };
45-
// NOTE: \r?
46-
// https://learn.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-options#multiline-mode
47-
private static readonly Regex s_getConnectionProperties =
48-
new Regex(@"^(?<pid><[^>]*>)\s\[.*""connection_name"",""(?<connection_name>[^""]*)"".*\]\r?$", RegexOptions.Multiline | RegexOptions.Compiled);
49-
5042
private readonly ITestOutputHelper _output;
5143

5244
public RabbitMQCtl(ITestOutputHelper output)
5345
{
5446
_output = output;
5547
}
5648

57-
public async Task CloseConnectionAsync(IConnection conn)
58-
{
59-
string pid = await GetConnectionPidAsync(conn.ClientProvidedName);
60-
await CloseConnectionAsync(pid);
61-
}
62-
63-
public Task AddUserAsync(string username, string password)
64-
{
65-
return ExecRabbitMQCtlAsync($"add_user {username} {password}");
66-
}
67-
68-
public Task ChangePasswordAsync(string username, string password)
69-
{
70-
return ExecRabbitMQCtlAsync($"change_password {username} {password}");
71-
}
72-
73-
public Task SetPermissionsAsync(string username, string conf, string write, string read)
74-
{
75-
return ExecRabbitMQCtlAsync($"set_permissions {username} \"{conf}\" \"{write}\" \"${read}\" ");
76-
}
77-
78-
public Task DeleteUserAsync(string username)
79-
{
80-
return ExecRabbitMQCtlAsync($"delete_user {username}");
81-
}
82-
8349
public async Task<string> ExecRabbitMQCtlAsync(string args)
8450
{
8551
try
@@ -139,28 +105,6 @@ private static ProcessStartInfo GetRabbitMqCtlStartInfo(string args)
139105
return CreateProcessStartInfo(path, args);
140106
}
141107

142-
private async Task<string> GetConnectionPidAsync(string connectionName)
143-
{
144-
string stdout = await ExecRabbitMQCtlAsync("list_connections --silent pid client_properties");
145-
Match match = s_getConnectionProperties.Match(stdout);
146-
while (match.Success)
147-
{
148-
if (match.Groups["connection_name"].Value == connectionName)
149-
{
150-
return match.Groups["pid"].Value;
151-
}
152-
153-
match = match.NextMatch();
154-
}
155-
156-
throw new Exception($"No connection found with name: {connectionName}");
157-
}
158-
159-
private Task CloseConnectionAsync(string pid)
160-
{
161-
return ExecRabbitMQCtlAsync($"close_connection \"{pid}\" \"Closed via rabbitmqctl\"");
162-
}
163-
164108
private static ProcessStartInfo CreateProcessStartInfo(string cmd, string arguments, string workDirectory = null)
165109
{
166110
return new ProcessStartInfo

projects/Test/Common/TestConnectionRecoveryBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ internal async Task<AutorecoveringConnection> CreateAutorecoveringConnectionWith
170170

171171
protected Task CloseConnectionAsync(IConnection conn)
172172
{
173-
return _rabbitMQCtl.CloseConnectionAsync(conn);
173+
return Util.CloseConnectionAsync(conn);
174174
}
175175

176176
protected Task CloseAndWaitForRecoveryAsync()

projects/Test/Common/Util.cs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Globalization;
4+
using System.Linq;
5+
using System.Threading.Tasks;
6+
using EasyNetQ.Management.Client;
7+
using RabbitMQ.Client;
38

49
namespace Test
510
{
611
public static class Util
712
{
13+
private static readonly TimeSpan s_closeConnectionDelay = TimeSpan.FromSeconds(2);
14+
private static readonly ManagementClient s_managementClient;
815
private static readonly bool s_isWindows = false;
916

1017
static Util()
1118
{
19+
var managementUri = new Uri("http://localhost:15672");
20+
s_managementClient = new ManagementClient(managementUri, "guest", "guest");
1221
s_isWindows = InitIsWindows();
1322
}
1423

@@ -33,5 +42,53 @@ private static bool InitIsWindows()
3342

3443
return false;
3544
}
45+
46+
public static async Task CloseConnectionAsync(IConnection conn)
47+
{
48+
ushort tries = 10;
49+
EasyNetQ.Management.Client.Model.Connection connectionToClose = null;
50+
do
51+
{
52+
IReadOnlyList<EasyNetQ.Management.Client.Model.Connection> connections;
53+
try
54+
{
55+
do
56+
{
57+
await Task.Delay(s_closeConnectionDelay);
58+
connections = await s_managementClient.GetConnectionsAsync();
59+
} while (connections.Count == 0);
60+
61+
connectionToClose = connections.Where(c0 =>
62+
string.Equals((string)c0.ClientProperties["connection_name"], conn.ClientProvidedName,
63+
StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();
64+
65+
if (connectionToClose == null)
66+
{
67+
tries--;
68+
}
69+
else
70+
{
71+
break;
72+
}
73+
}
74+
catch (ArgumentNullException)
75+
{
76+
// Sometimes we see this in GitHub CI
77+
tries--;
78+
}
79+
} while (tries > 0);
80+
81+
if (tries == 0)
82+
{
83+
throw new InvalidOperationException($"Could not delete connection: '{conn.ClientProvidedName}'");
84+
}
85+
86+
if (connectionToClose == null)
87+
{
88+
throw new InvalidOperationException($"connectionToClose should not be null here");
89+
}
90+
91+
await s_managementClient.CloseConnectionAsync(connectionToClose);
92+
}
3693
}
3794
}

0 commit comments

Comments
 (0)