@@ -37,7 +37,7 @@ internal abstract class Cluster : ICluster
37
37
{
38
38
#region static
39
39
// static fields
40
- private static readonly TimeSpan __minHeartbeatInterval = TimeSpan . FromMilliseconds ( 500 ) ;
40
+ private static readonly TimeSpan __minHeartbeatIntervalDefault = TimeSpan . FromMilliseconds ( 500 ) ;
41
41
private static readonly SemanticVersion __minSupportedServerVersion = new SemanticVersion ( 2 , 6 , 0 ) ;
42
42
private static readonly IServerSelector __randomServerSelector = new RandomServerSelector ( ) ;
43
43
private static readonly Range < int > __supportedWireVersionRange = new Range < int > ( 2 , 9 ) ;
@@ -61,6 +61,7 @@ internal abstract class Cluster : ICluster
61
61
#endregion
62
62
63
63
// fields
64
+ private readonly TimeSpan _minHeartbeatInterval = __minHeartbeatIntervalDefault ;
64
65
private readonly IClusterClock _clusterClock = new ClusterClock ( ) ;
65
66
private readonly ClusterId _clusterId ;
66
67
private CryptClient _cryptClient = null ;
@@ -75,6 +76,7 @@ internal abstract class Cluster : ICluster
75
76
private readonly ICoreServerSessionPool _serverSessionPool ;
76
77
private readonly ClusterSettings _settings ;
77
78
private readonly InterlockedInt32 _state ;
79
+ private readonly InterlockedInt32 _rapidHeartbeatTimerCallbackState ;
78
80
79
81
private readonly Action < ClusterDescriptionChangedEvent > _descriptionChangedEventHandler ;
80
82
private readonly Action < ClusterSelectingServerEvent > _selectingServerEventHandler ;
@@ -88,6 +90,7 @@ protected Cluster(ClusterSettings settings, IClusterableServerFactory serverFact
88
90
_serverFactory = Ensure . IsNotNull ( serverFactory , nameof ( serverFactory ) ) ;
89
91
Ensure . IsNotNull ( eventSubscriber , nameof ( eventSubscriber ) ) ;
90
92
_state = new InterlockedInt32 ( State . Initial ) ;
93
+ _rapidHeartbeatTimerCallbackState = new InterlockedInt32 ( RapidHeartbeatTimerCallbackState . NotRunning ) ;
91
94
92
95
_clusterId = new ClusterId ( ) ;
93
96
_description = ClusterDescription . CreateInitial ( _clusterId , _settings . ConnectionMode ) ;
@@ -178,7 +181,7 @@ private void EnterServerSelectionWaitQueue()
178
181
179
182
if ( ++ _serverSelectionWaitQueueSize == 1 )
180
183
{
181
- _rapidHeartbeatTimer . Change ( TimeSpan . Zero , __minHeartbeatInterval ) ;
184
+ _rapidHeartbeatTimer . Change ( TimeSpan . Zero , _minHeartbeatInterval ) ;
182
185
}
183
186
}
184
187
}
@@ -208,15 +211,23 @@ public virtual void Initialize()
208
211
209
212
private void RapidHeartbeatTimerCallback ( object args )
210
213
{
211
- try
214
+ // avoid requesting heartbeat reentrantly
215
+ if ( _rapidHeartbeatTimerCallbackState . TryChange ( RapidHeartbeatTimerCallbackState . NotRunning , RapidHeartbeatTimerCallbackState . Running ) )
212
216
{
213
- RequestHeartbeat ( ) ;
214
- }
215
- catch
216
- {
217
- // TODO: Trace this
218
- // If we don't protect this call, we could
219
- // take down the app domain.
217
+ try
218
+ {
219
+ RequestHeartbeat ( ) ;
220
+ }
221
+ catch
222
+ {
223
+ // TODO: Trace this
224
+ // If we don't protect this call, we could
225
+ // take down the app domain.
226
+ }
227
+ finally
228
+ {
229
+ _rapidHeartbeatTimerCallbackState . TryChange ( RapidHeartbeatTimerCallbackState . NotRunning ) ;
230
+ }
220
231
}
221
232
}
222
233
@@ -596,5 +607,11 @@ private static class State
596
607
public const int Open = 1 ;
597
608
public const int Disposed = 2 ;
598
609
}
610
+
611
+ private static class RapidHeartbeatTimerCallbackState
612
+ {
613
+ public const int NotRunning = 0 ;
614
+ public const int Running = 1 ;
615
+ }
599
616
}
600
617
}
0 commit comments