Use shared eventLoopGroup in Reactor2TcpClient
This commit is contained in:
parent
49e90575e9
commit
5538863dc9
|
|
@ -80,7 +80,7 @@ abstract class AbstractPromiseToListenableFutureAdapter<S, T> implements Listena
|
||||||
@Override
|
@Override
|
||||||
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
|
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
|
||||||
S result = this.promise.await(timeout, unit);
|
S result = this.promise.await(timeout, unit);
|
||||||
if (result == null) {
|
if (!this.promise.isComplete()) {
|
||||||
throw new TimeoutException();
|
throw new TimeoutException();
|
||||||
}
|
}
|
||||||
return adapt(result);
|
return adapt(result);
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,11 @@ import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import io.netty.channel.nio.NioEventLoopGroup;
|
import io.netty.channel.nio.NioEventLoopGroup;
|
||||||
|
import io.netty.util.concurrent.Future;
|
||||||
|
import io.netty.util.concurrent.FutureListener;
|
||||||
import org.reactivestreams.Publisher;
|
import org.reactivestreams.Publisher;
|
||||||
import reactor.Environment;
|
import reactor.Environment;
|
||||||
import reactor.core.config.ConfigurationReader;
|
import reactor.core.config.ConfigurationReader;
|
||||||
|
|
@ -79,6 +82,10 @@ public class Reactor2TcpClient<P> implements TcpOperations<P> {
|
||||||
private final List<TcpClient<Message<P>, Message<P>>> tcpClients =
|
private final List<TcpClient<Message<P>, Message<P>>> tcpClients =
|
||||||
new ArrayList<TcpClient<Message<P>, Message<P>>>();
|
new ArrayList<TcpClient<Message<P>, Message<P>>>();
|
||||||
|
|
||||||
|
private final NioEventLoopGroup eventLoopGroup;
|
||||||
|
|
||||||
|
private boolean stopping;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A constructor that creates a {@link TcpClientSpec TcpClientSpec} factory
|
* A constructor that creates a {@link TcpClientSpec TcpClientSpec} factory
|
||||||
|
|
@ -95,7 +102,7 @@ public class Reactor2TcpClient<P> implements TcpOperations<P> {
|
||||||
*/
|
*/
|
||||||
public Reactor2TcpClient(final String host, final int port, final Codec<Buffer, Message<P>, Message<P>> codec) {
|
public Reactor2TcpClient(final String host, final int port, final Codec<Buffer, Message<P>, Message<P>> codec) {
|
||||||
|
|
||||||
final NioEventLoopGroup eventLoopGroup = initEventLoopGroup();
|
this.eventLoopGroup = initEventLoopGroup();
|
||||||
|
|
||||||
this.tcpClientSpecFactory = new TcpClientFactory<Message<P>, Message<P>>() {
|
this.tcpClientSpecFactory = new TcpClientFactory<Message<P>, Message<P>>() {
|
||||||
|
|
||||||
|
|
@ -110,7 +117,7 @@ public class Reactor2TcpClient<P> implements TcpOperations<P> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private NioEventLoopGroup initEventLoopGroup() {
|
private static NioEventLoopGroup initEventLoopGroup() {
|
||||||
int ioThreadCount;
|
int ioThreadCount;
|
||||||
try {
|
try {
|
||||||
ioThreadCount = Integer.parseInt(System.getProperty("reactor.tcp.ioThreadCount"));
|
ioThreadCount = Integer.parseInt(System.getProperty("reactor.tcp.ioThreadCount"));
|
||||||
|
|
@ -139,13 +146,27 @@ public class Reactor2TcpClient<P> implements TcpOperations<P> {
|
||||||
public Reactor2TcpClient(TcpClientFactory<Message<P>, Message<P>> tcpClientSpecFactory) {
|
public Reactor2TcpClient(TcpClientFactory<Message<P>, Message<P>> tcpClientSpecFactory) {
|
||||||
Assert.notNull(tcpClientSpecFactory, "'tcpClientClientFactory' must not be null");
|
Assert.notNull(tcpClientSpecFactory, "'tcpClientClientFactory' must not be null");
|
||||||
this.tcpClientSpecFactory = tcpClientSpecFactory;
|
this.tcpClientSpecFactory = tcpClientSpecFactory;
|
||||||
|
this.eventLoopGroup = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<Void> connect(final TcpConnectionHandler<P> connectionHandler) {
|
public ListenableFuture<Void> connect(final TcpConnectionHandler<P> connectionHandler) {
|
||||||
Assert.notNull(connectionHandler, "'connectionHandler' must not be null");
|
Assert.notNull(connectionHandler, "'connectionHandler' must not be null");
|
||||||
Promise<Void> promise = createTcpClient().start(new MessageChannelStreamHandler<P>(connectionHandler));
|
|
||||||
|
TcpClient<Message<P>, Message<P>> tcpClient;
|
||||||
|
synchronized (this.tcpClients) {
|
||||||
|
if (this.stopping) {
|
||||||
|
IllegalStateException ex = new IllegalStateException("Shutting down.");
|
||||||
|
connectionHandler.afterConnectFailure(ex);
|
||||||
|
return new PassThroughPromiseToListenableFutureAdapter<Void>(Promises.<Void>error(ex));
|
||||||
|
}
|
||||||
|
tcpClient = NetStreams.tcpClient(REACTOR_TCP_CLIENT_TYPE, this.tcpClientSpecFactory);
|
||||||
|
this.tcpClients.add(tcpClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
Promise<Void> promise = tcpClient.start(new MessageChannelStreamHandler<P>(connectionHandler));
|
||||||
|
|
||||||
return new PassThroughPromiseToListenableFutureAdapter<Void>(
|
return new PassThroughPromiseToListenableFutureAdapter<Void>(
|
||||||
promise.onError(new Consumer<Throwable>() {
|
promise.onError(new Consumer<Throwable>() {
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -161,43 +182,62 @@ public class Reactor2TcpClient<P> implements TcpOperations<P> {
|
||||||
Assert.notNull(connectionHandler, "'connectionHandler' must not be null");
|
Assert.notNull(connectionHandler, "'connectionHandler' must not be null");
|
||||||
Assert.notNull(strategy, "'reconnectStrategy' must not be null");
|
Assert.notNull(strategy, "'reconnectStrategy' must not be null");
|
||||||
|
|
||||||
Stream<Tuple2<InetSocketAddress, Integer>> stream = createTcpClient().start(
|
TcpClient<Message<P>, Message<P>> tcpClient;
|
||||||
|
synchronized (this.tcpClients) {
|
||||||
|
if (this.stopping) {
|
||||||
|
IllegalStateException ex = new IllegalStateException("Shutting down.");
|
||||||
|
connectionHandler.afterConnectFailure(ex);
|
||||||
|
return new PassThroughPromiseToListenableFutureAdapter<Void>(Promises.<Void>error(ex));
|
||||||
|
}
|
||||||
|
tcpClient = NetStreams.tcpClient(REACTOR_TCP_CLIENT_TYPE, this.tcpClientSpecFactory);
|
||||||
|
this.tcpClients.add(tcpClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream<Tuple2<InetSocketAddress, Integer>> stream = tcpClient.start(
|
||||||
new MessageChannelStreamHandler<P>(connectionHandler),
|
new MessageChannelStreamHandler<P>(connectionHandler),
|
||||||
new ReactorReconnectAdapter(strategy));
|
new ReactorReconnectAdapter(strategy));
|
||||||
|
|
||||||
return new PassThroughPromiseToListenableFutureAdapter<Void>(stream.next().after());
|
return new PassThroughPromiseToListenableFutureAdapter<Void>(stream.next().after());
|
||||||
}
|
}
|
||||||
|
|
||||||
private TcpClient<Message<P>, Message<P>> createTcpClient() {
|
|
||||||
Class<NettyTcpClient> type = REACTOR_TCP_CLIENT_TYPE;
|
|
||||||
TcpClient<Message<P>, Message<P>> tcpClient = NetStreams.tcpClient(type, this.tcpClientSpecFactory);
|
|
||||||
synchronized (this.tcpClients) {
|
|
||||||
this.tcpClients.add(tcpClient);
|
|
||||||
}
|
|
||||||
return tcpClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<Void> shutdown() {
|
public ListenableFuture<Void> shutdown() {
|
||||||
final List<TcpClient<Message<P>, Message<P>>> readOnlyClients;
|
|
||||||
synchronized (this.tcpClients) {
|
synchronized (this.tcpClients) {
|
||||||
readOnlyClients = new ArrayList<TcpClient<Message<P>, Message<P>>>(this.tcpClients);
|
this.stopping = true;
|
||||||
}
|
}
|
||||||
Promise<Void> promise = Streams.from(readOnlyClients)
|
Promise<Void> promise = Streams.from(this.tcpClients)
|
||||||
.flatMap(new Function<TcpClient<Message<P>, Message<P>>, Promise<Void>>() {
|
.flatMap(new Function<TcpClient<Message<P>, Message<P>>, Promise<Void>>() {
|
||||||
@Override
|
@Override
|
||||||
public Promise<Void> apply(final TcpClient<Message<P>, Message<P>> client) {
|
public Promise<Void> apply(final TcpClient<Message<P>, Message<P>> client) {
|
||||||
return client.shutdown().onComplete(new Consumer<Promise<Void>>() {
|
return client.shutdown().onComplete(new Consumer<Promise<Void>>() {
|
||||||
@Override
|
@Override
|
||||||
public void accept(Promise<Void> voidPromise) {
|
public void accept(Promise<Void> voidPromise) {
|
||||||
synchronized (tcpClients) {
|
tcpClients.remove(client);
|
||||||
tcpClients.remove(client);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.next();
|
.next();
|
||||||
|
if (this.eventLoopGroup != null) {
|
||||||
|
final Promise<Void> eventLoopPromise = Promises.prepare();
|
||||||
|
promise.onComplete(new Consumer<Promise<Void>>() {
|
||||||
|
@Override
|
||||||
|
public void accept(Promise<Void> voidPromise) {
|
||||||
|
eventLoopGroup.shutdownGracefully().addListener(new FutureListener<Object>() {
|
||||||
|
@Override
|
||||||
|
public void operationComplete(Future<Object> future) throws Exception {
|
||||||
|
if (future.isSuccess()) {
|
||||||
|
eventLoopPromise.onComplete();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
eventLoopPromise.onError(future.cause());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
promise = eventLoopPromise;
|
||||||
|
}
|
||||||
return new PassThroughPromiseToListenableFutureAdapter<Void>(promise);
|
return new PassThroughPromiseToListenableFutureAdapter<Void>(promise);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue