Skip to content

Commit 803aa12

Browse files
Merge pull request #397 from nazmul1985/master
fixed 'System.ObjectDisposedException' when closing/disposing connection
2 parents b67e4ce + 9fb7744 commit 803aa12

File tree

1 file changed

+91
-61
lines changed

1 file changed

+91
-61
lines changed

projects/client/RabbitMQ.Client/src/client/impl/Connection.cs

Lines changed: 91 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,11 @@ public class Connection : IConnection
107107
private Timer _heartbeatReadTimer;
108108
private AutoResetEvent m_heartbeatRead = new AutoResetEvent(false);
109109

110+
private readonly object _heartBeatReadLock = new object();
111+
private readonly object _heartBeatWriteLock = new object();
112+
private bool m_hasDisposedHeartBeatReadTimer;
113+
private bool m_hasDisposedHeartBeatWriteTimer;
114+
110115
#if CORECLR
111116
private static string version = typeof(Connection).GetTypeInfo().Assembly
112117
.GetCustomAttribute<AssemblyInformationalVersionAttribute>()
@@ -1012,6 +1017,8 @@ public void MaybeStartHeartbeatTimers()
10121017
{
10131018
if (Heartbeat != 0)
10141019
{
1020+
m_hasDisposedHeartBeatReadTimer = false;
1021+
m_hasDisposedHeartBeatWriteTimer = false;
10151022
#if NETFX_CORE
10161023
_heartbeatWriteTimer = new Timer(HeartbeatWriteTimerCallback);
10171024
_heartbeatReadTimer = new Timer(HeartbeatReadTimerCallback);
@@ -1042,97 +1049,120 @@ public void StartMainLoop(bool useBackgroundThread)
10421049

10431050
public void HeartbeatReadTimerCallback(object state)
10441051
{
1045-
bool shouldTerminate = false;
1046-
try
1052+
lock (_heartBeatReadLock)
10471053
{
1048-
if (!m_closed)
1054+
if (m_hasDisposedHeartBeatReadTimer)
1055+
{
1056+
return;
1057+
}
1058+
bool shouldTerminate = false;
1059+
try
10491060
{
1050-
if (!m_heartbeatRead.WaitOne(0))
1061+
if (!m_closed)
10511062
{
1052-
m_missedHeartbeats++;
1063+
if (!m_heartbeatRead.WaitOne(0))
1064+
{
1065+
m_missedHeartbeats++;
1066+
}
1067+
else
1068+
{
1069+
m_missedHeartbeats = 0;
1070+
}
1071+
1072+
// We check against 8 = 2 * 4 because we need to wait for at
1073+
// least two complete heartbeat setting intervals before
1074+
// complaining, and we've set the socket timeout to a quarter
1075+
// of the heartbeat setting in setHeartbeat above.
1076+
if (m_missedHeartbeats > 2 * 4)
1077+
{
1078+
String description = String.Format("Heartbeat missing with heartbeat == {0} seconds", m_heartbeat);
1079+
var eose = new EndOfStreamException(description);
1080+
ESLog.Error(description, eose);
1081+
m_shutdownReport.Add(new ShutdownReportEntry(description, eose));
1082+
HandleMainLoopException(
1083+
new ShutdownEventArgs(ShutdownInitiator.Library, 0, "End of stream", eose));
1084+
shouldTerminate = true;
1085+
}
10531086
}
1054-
else
1087+
1088+
if (shouldTerminate)
10551089
{
1056-
m_missedHeartbeats = 0;
1090+
TerminateMainloop();
1091+
FinishClose();
10571092
}
1058-
1059-
// We check against 8 = 2 * 4 because we need to wait for at
1060-
// least two complete heartbeat setting intervals before
1061-
// complaining, and we've set the socket timeout to a quarter
1062-
// of the heartbeat setting in setHeartbeat above.
1063-
if (m_missedHeartbeats > 2 * 4)
1093+
else if (_heartbeatReadTimer != null)
10641094
{
1065-
String description = String.Format("Heartbeat missing with heartbeat == {0} seconds", m_heartbeat);
1066-
var eose = new EndOfStreamException(description);
1067-
ESLog.Error(description, eose);
1068-
m_shutdownReport.Add(new ShutdownReportEntry(description, eose));
1069-
HandleMainLoopException(
1070-
new ShutdownEventArgs(ShutdownInitiator.Library, 0, "End of stream", eose));
1071-
shouldTerminate = true;
1095+
_heartbeatReadTimer.Change(Heartbeat * 1000, Timeout.Infinite);
10721096
}
10731097
}
1074-
1075-
if (shouldTerminate)
1098+
catch (ObjectDisposedException)
10761099
{
1077-
TerminateMainloop();
1078-
FinishClose();
1100+
// timer is already disposed,
1101+
// e.g. due to shutdown
10791102
}
1080-
else if (_heartbeatReadTimer != null)
1103+
catch (NullReferenceException)
10811104
{
1082-
_heartbeatReadTimer.Change(Heartbeat * 1000, Timeout.Infinite);
1105+
// timer has already been disposed from a different thread after null check
1106+
// this event should be rare
10831107
}
10841108
}
1085-
catch (ObjectDisposedException)
1086-
{
1087-
// timer is already disposed,
1088-
// e.g. due to shutdown
1089-
}
1090-
catch (NullReferenceException)
1091-
{
1092-
// timer has already been disposed from a different thread after null check
1093-
// this event should be rare
1094-
}
10951109
}
10961110

10971111
public void HeartbeatWriteTimerCallback(object state)
10981112
{
1099-
bool shouldTerminate = false;
1100-
try
1113+
lock (_heartBeatWriteLock)
11011114
{
1115+
if (m_hasDisposedHeartBeatWriteTimer)
1116+
{
1117+
return;
1118+
}
1119+
bool shouldTerminate = false;
11021120
try
11031121
{
1104-
if (!m_closed)
1122+
try
11051123
{
1106-
WriteFrame(m_heartbeatFrame);
1124+
if (!m_closed)
1125+
{
1126+
WriteFrame(m_heartbeatFrame);
1127+
}
1128+
}
1129+
catch (Exception e)
1130+
{
1131+
HandleMainLoopException(new ShutdownEventArgs(
1132+
ShutdownInitiator.Library,
1133+
0,
1134+
"End of stream",
1135+
e));
1136+
shouldTerminate = true;
11071137
}
1108-
}
1109-
catch (Exception e)
1110-
{
1111-
HandleMainLoopException(new ShutdownEventArgs(
1112-
ShutdownInitiator.Library,
1113-
0,
1114-
"End of stream",
1115-
e));
1116-
shouldTerminate = true;
1117-
}
11181138

1119-
if (m_closed || shouldTerminate)
1120-
{
1121-
TerminateMainloop();
1122-
FinishClose();
1139+
if (m_closed || shouldTerminate)
1140+
{
1141+
TerminateMainloop();
1142+
FinishClose();
1143+
}
11231144
}
1124-
}
1125-
catch (ObjectDisposedException)
1126-
{
1127-
// timer is already disposed,
1128-
// e.g. due to shutdown
1145+
catch (ObjectDisposedException)
1146+
{
1147+
// timer is already disposed,
1148+
// e.g. due to shutdown
1149+
} /**/
11291150
}
11301151
}
11311152

11321153
protected void MaybeStopHeartbeatTimers()
11331154
{
1134-
MaybeDisposeTimer(ref _heartbeatReadTimer);
1135-
MaybeDisposeTimer(ref _heartbeatWriteTimer);
1155+
lock (_heartBeatReadLock)
1156+
{
1157+
MaybeDisposeTimer(ref _heartbeatReadTimer);
1158+
m_hasDisposedHeartBeatReadTimer = true;
1159+
}
1160+
1161+
lock (_heartBeatWriteLock)
1162+
{
1163+
MaybeDisposeTimer(ref _heartbeatWriteTimer);
1164+
m_hasDisposedHeartBeatWriteTimer = true;
1165+
}
11361166
}
11371167

11381168
private void MaybeDisposeTimer(ref Timer timer)

0 commit comments

Comments
 (0)