15
15
16
16
package com .rabbitmq .client .impl ;
17
17
18
+ import com .rabbitmq .client .ConnectionFactory ;
19
+ import com .rabbitmq .client .MetricsCollector ;
20
+ import com .rabbitmq .client .NoOpMetricsCollector ;
21
+ import com .rabbitmq .client .ShutdownSignalException ;
22
+ import com .rabbitmq .utility .IntAllocator ;
23
+ import org .slf4j .Logger ;
24
+ import org .slf4j .LoggerFactory ;
25
+
18
26
import java .io .IOException ;
19
27
import java .util .HashMap ;
20
28
import java .util .HashSet ;
21
29
import java .util .Map ;
22
30
import java .util .Set ;
23
- import java .util .concurrent .CountDownLatch ;
24
- import java .util .concurrent .ExecutorService ;
25
- import java .util .concurrent .Executors ;
26
- import java .util .concurrent .ThreadFactory ;
27
- import java .util .concurrent .TimeUnit ;
28
-
29
- import com .rabbitmq .client .NoOpMetricsCollector ;
30
- import com .rabbitmq .client .ShutdownSignalException ;
31
- import com .rabbitmq .client .MetricsCollector ;
32
- import com .rabbitmq .utility .IntAllocator ;
31
+ import java .util .concurrent .*;
33
32
34
33
/**
35
34
* Manages a set of channels, indexed by channel number (<code><b>1.._channelMax</b></code>).
36
35
*/
37
36
public class ChannelManager {
37
+
38
+ private static final Logger LOGGER = LoggerFactory .getLogger (ChannelManager .class );
39
+
38
40
/** Monitor for <code>_channelMap</code> and <code>channelNumberAllocator</code> */
39
41
private final Object monitor = new Object ();
40
42
/** Mapping from <code><b>1.._channelMax</b></code> to {@link ChannelN} instance */
@@ -50,6 +52,8 @@ public class ChannelManager {
50
52
private ExecutorService shutdownExecutor ;
51
53
private final ThreadFactory threadFactory ;
52
54
55
+ private int channelShutdownTimeout = (int ) ((ConnectionFactory .DEFAULT_HEARTBEAT * 1.05 ) * 1000 );
56
+
53
57
protected final MetricsCollector metricsCollector ;
54
58
55
59
public int getChannelMax (){
@@ -97,14 +101,33 @@ public ChannelN getChannel(int channelNumber) {
97
101
* Handle shutdown. All the managed {@link com.rabbitmq.client.Channel Channel}s are shutdown.
98
102
* @param signal reason for shutdown
99
103
*/
100
- public void handleSignal (ShutdownSignalException signal ) {
104
+ public void handleSignal (final ShutdownSignalException signal ) {
101
105
Set <ChannelN > channels ;
102
106
synchronized (this .monitor ) {
103
107
channels = new HashSet <ChannelN >(_channelMap .values ());
104
108
}
105
- for (ChannelN channel : channels ) {
109
+
110
+ for (final ChannelN channel : channels ) {
106
111
releaseChannelNumber (channel );
107
- channel .processShutdownSignal (signal , true , true );
112
+ // async shutdown if possible
113
+ // see https://github.com/rabbitmq/rabbitmq-java-client/issues/194
114
+ Runnable channelShutdownRunnable = new Runnable () {
115
+ @ Override
116
+ public void run () {
117
+ channel .processShutdownSignal (signal , true , true );
118
+ }
119
+ };
120
+ if (this .shutdownExecutor == null ) {
121
+ channelShutdownRunnable .run ();
122
+ } else {
123
+ Future <?> channelShutdownTask = this .shutdownExecutor .submit (channelShutdownRunnable );
124
+ try {
125
+ channelShutdownTask .get (channelShutdownTimeout , TimeUnit .MILLISECONDS );
126
+ } catch (Exception e ) {
127
+ LOGGER .warn ("Couldn't properly close channel {} on shutdown after waiting for {} ms" , channel .getChannelNumber (), channelShutdownTimeout );
128
+ channelShutdownTask .cancel (true );
129
+ }
130
+ }
108
131
shutdownSet .add (channel .getShutdownLatch ());
109
132
channel .notifyListeners ();
110
133
}
@@ -225,4 +248,16 @@ public ExecutorService getShutdownExecutor() {
225
248
public void setShutdownExecutor (ExecutorService shutdownExecutor ) {
226
249
this .shutdownExecutor = shutdownExecutor ;
227
250
}
251
+
252
+ /**
253
+ * Set the shutdown timeout for channels.
254
+ * This is the amount of time the manager waits for a channel to
255
+ * shutdown before giving up.
256
+ * Works only when the {@code shutdownExecutor} property is set.
257
+ * Default to {@link com.rabbitmq.client.ConnectionFactory#DEFAULT_HEARTBEAT} + 5 % seconds
258
+ * @param channelShutdownTimeout shutdown timeout in milliseconds
259
+ */
260
+ public void setChannelShutdownTimeout (int channelShutdownTimeout ) {
261
+ this .channelShutdownTimeout = channelShutdownTimeout ;
262
+ }
228
263
}
0 commit comments