Skip to content

Commit 55a33e2

Browse files
authored
Merge pull request #1431 from rabbitmq/rabbitmq-dotnet-client-1429
Fix #1429
2 parents e1ffbb5 + 21ecfb1 commit 55a33e2

File tree

4 files changed

+72
-46
lines changed

4 files changed

+72
-46
lines changed

projects/RabbitMQ.Client/client/api/IChannelExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ public static void ExchangeDeclare(this IChannel channel, string exchange, strin
208208
public static ValueTask ExchangeDeclareAsync(this IChannel channel, string exchange, string type, bool durable = false, bool autoDelete = false,
209209
IDictionary<string, object> arguments = null)
210210
{
211-
return channel.ExchangeDeclareAsync(exchange, type, durable, autoDelete, arguments);
211+
return channel.ExchangeDeclareAsync(exchange, type, false, durable, autoDelete, arguments);
212212
}
213213

214214
/// <summary>

projects/RabbitMQ.Client/client/api/ICredentialsRefresher.cs

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
//---------------------------------------------------------------------------
3131

3232
using System;
33-
using System.Collections.Generic;
33+
using System.Collections.Concurrent;
3434
using System.Diagnostics.Tracing;
3535
namespace RabbitMQ.Client
3636
{
@@ -57,11 +57,13 @@ public class TimerBasedCredentialRefresherEventSource : EventSource
5757
public void TriggeredTimer(string name) => WriteEvent(4, "TriggeredTimer", name);
5858
[Event(5)]
5959
public void RefreshedCredentials(string name, bool succesfully) => WriteEvent(5, "RefreshedCredentials", name, succesfully);
60+
[Event(6)]
61+
public void AlreadyRegistered(string name) => WriteEvent(6, "AlreadyRegistered", name);
6062
}
6163

6264
public class TimerBasedCredentialRefresher : ICredentialsRefresher
6365
{
64-
private Dictionary<ICredentialsProvider, System.Timers.Timer> _registrations = new Dictionary<ICredentialsProvider, System.Timers.Timer>();
66+
private readonly ConcurrentDictionary<ICredentialsProvider, System.Timers.Timer> _registrations = new();
6567

6668
public ICredentialsProvider Register(ICredentialsProvider provider, ICredentialsRefresher.NotifyCredentialRefreshed callback)
6769
{
@@ -70,25 +72,31 @@ public ICredentialsProvider Register(ICredentialsProvider provider, ICredentials
7072
return provider;
7173
}
7274

73-
_registrations.Add(provider, scheduleTimer(provider, callback));
74-
TimerBasedCredentialRefresherEventSource.Log.Registered(provider.Name);
75+
if (_registrations.TryAdd(provider, scheduleTimer(provider, callback)))
76+
{
77+
TimerBasedCredentialRefresherEventSource.Log.Registered(provider.Name);
78+
}
79+
else
80+
{
81+
TimerBasedCredentialRefresherEventSource.Log.AlreadyRegistered(provider.Name);
82+
}
83+
7584
return provider;
7685
}
7786

7887
public bool Unregister(ICredentialsProvider provider)
7988
{
80-
if (!_registrations.ContainsKey(provider))
89+
if (_registrations.TryRemove(provider, out System.Timers.Timer timer))
8190
{
82-
return false;
83-
}
84-
85-
var timer = _registrations[provider];
86-
if (timer != null)
87-
{
88-
TimerBasedCredentialRefresherEventSource.Log.Unregistered(provider.Name);
89-
timer.Stop();
90-
_registrations.Remove(provider);
91-
timer.Dispose();
91+
try
92+
{
93+
TimerBasedCredentialRefresherEventSource.Log.Unregistered(provider.Name);
94+
timer.Stop();
95+
}
96+
finally
97+
{
98+
timer.Dispose();
99+
}
92100
return true;
93101
}
94102
else

projects/Test/OAuth2/TestOAuth2.cs

Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,14 @@ public OAuth2Options(Mode mode)
5858
public int TokenExpiresInSeconds => 60;
5959
}
6060

61-
public class TestOAuth2
61+
public class TestOAuth2 : IAsyncLifetime
6262
{
6363
private const string Exchange = "test_direct";
6464

6565
private readonly AutoResetEvent _doneEvent = new AutoResetEvent(false);
6666
private readonly ITestOutputHelper _testOutputHelper;
67-
private readonly IConnection _connection;
67+
private readonly IConnectionFactory _connectionFactory;
68+
private IConnection _connection;
6869
private readonly int _tokenExpiresInSeconds;
6970

7071
public TestOAuth2(ITestOutputHelper testOutputHelper)
@@ -75,61 +76,76 @@ public TestOAuth2(ITestOutputHelper testOutputHelper)
7576
Mode mode = (Mode)Enum.Parse(typeof(Mode), modeStr.ToLowerInvariant());
7677
var options = new OAuth2Options(mode);
7778

78-
var connectionFactory = new ConnectionFactory
79+
_connectionFactory = new ConnectionFactory
7980
{
8081
AutomaticRecoveryEnabled = true,
82+
DispatchConsumersAsync = true,
8183
CredentialsProvider = GetCredentialsProvider(options),
8284
CredentialsRefresher = GetCredentialsRefresher(),
8385
ClientProvidedName = nameof(TestOAuth2)
8486
};
8587

86-
_connection = connectionFactory.CreateConnection();
8788
_tokenExpiresInSeconds = options.TokenExpiresInSeconds;
8889
}
8990

91+
public async Task InitializeAsync()
92+
{
93+
_connection = await _connectionFactory.CreateConnectionAsync();
94+
}
95+
96+
public async Task DisposeAsync()
97+
{
98+
await _connection.CloseAsync();
99+
_connection.Dispose();
100+
}
101+
90102
[Fact]
91103
public async void IntegrationTest()
92104
{
93-
using (_connection)
105+
using (IChannel publishChannel = await DeclarePublisherAsync())
106+
using (IChannel consumeChannel = await DeclareConsumerAsync())
94107
{
95-
using (IChannel publisher = declarePublisher())
96-
using (IChannel subscriber = await declareConsumer())
97-
{
98-
await Publish(publisher);
99-
Consume(subscriber);
108+
await PublishAsync(publishChannel);
109+
Consume(consumeChannel);
100110

101-
if (_tokenExpiresInSeconds > 0)
111+
if (_tokenExpiresInSeconds > 0)
112+
{
113+
for (int i = 0; i < 4; i++)
102114
{
103-
for (int i = 0; i < 4; i++)
104-
{
105-
_testOutputHelper.WriteLine("Wait until Token expires. Attempt #" + (i + 1));
115+
_testOutputHelper.WriteLine("Wait until Token expires. Attempt #" + (i + 1));
106116

107-
await Task.Delay(TimeSpan.FromSeconds(_tokenExpiresInSeconds + 10));
108-
_testOutputHelper.WriteLine("Resuming ..");
117+
await Task.Delay(TimeSpan.FromSeconds(_tokenExpiresInSeconds + 10));
118+
_testOutputHelper.WriteLine("Resuming ..");
109119

110-
await Publish(publisher);
111-
_doneEvent.Reset();
120+
await PublishAsync(publishChannel);
121+
_doneEvent.Reset();
112122

113-
Consume(subscriber);
114-
}
115-
}
116-
else
117-
{
118-
throw new InvalidOperationException();
123+
Consume(consumeChannel);
119124
}
120125
}
126+
else
127+
{
128+
Assert.Fail("_tokenExpiresInSeconds is NOT greater than 0");
129+
}
121130
}
122131
}
123132

124-
private IChannel declarePublisher()
133+
[Fact]
134+
public async void SecondConnectionCrashes_GH1429()
135+
{
136+
// https://github.com/rabbitmq/rabbitmq-dotnet-client/issues/1429
137+
using IConnection secondConnection = await _connectionFactory.CreateConnectionAsync();
138+
}
139+
140+
private async Task<IChannel> DeclarePublisherAsync()
125141
{
126-
IChannel publisher = _connection.CreateChannel();
127-
publisher.ConfirmSelect();
128-
publisher.ExchangeDeclare("test_direct", ExchangeType.Direct, true, false);
142+
IChannel publisher = await _connection.CreateChannelAsync();
143+
await publisher.ConfirmSelectAsync();
144+
await publisher.ExchangeDeclareAsync("test_direct", ExchangeType.Direct, true, false);
129145
return publisher;
130146
}
131147

132-
private async Task Publish(IChannel publisher)
148+
private async Task PublishAsync(IChannel publisher)
133149
{
134150
const string message = "Hello World!";
135151

@@ -146,7 +162,7 @@ private async Task Publish(IChannel publisher)
146162
_testOutputHelper.WriteLine("Confirmed Sent message");
147163
}
148164

149-
private async ValueTask<IChannel> declareConsumer()
165+
private async ValueTask<IChannel> DeclareConsumerAsync()
150166
{
151167
IChannel subscriber = _connection.CreateChannel();
152168
await subscriber.QueueDeclareAsync(queue: "testqueue", passive: false, true, false, false, arguments: null);

projects/Test/Unit/APIApproval.Approve.verified.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -850,6 +850,8 @@ namespace RabbitMQ.Client
850850
{
851851
public TimerBasedCredentialRefresherEventSource() { }
852852
public static RabbitMQ.Client.TimerBasedCredentialRefresherEventSource Log { get; }
853+
[System.Diagnostics.Tracing.Event(6)]
854+
public void AlreadyRegistered(string name) { }
853855
[System.Diagnostics.Tracing.Event(5)]
854856
public void RefreshedCredentials(string name, bool succesfully) { }
855857
[System.Diagnostics.Tracing.Event(1)]

0 commit comments

Comments
 (0)