net.dongliu.prettypb.rpc.RpcClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of prettypb-rpc Show documentation
Show all versions of prettypb-rpc Show documentation
proto rpc libs, compatible with proto-rpc-pro
package net.dongliu.prettypb.rpc;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import net.dongliu.prettypb.rpc.client.*;
import net.dongliu.prettypb.rpc.config.ServerChangedNotifier;
import net.dongliu.prettypb.rpc.config.ServerProvider;
import net.dongliu.prettypb.rpc.exception.ServiceException;
import net.dongliu.prettypb.rpc.listener.TcpConnectionEventListener;
import net.dongliu.prettypb.rpc.protocol.RpcRequest;
import net.dongliu.prettypb.rpc.protocol.ServerInfo;
import net.dongliu.prettypb.runtime.ExtensionRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
/**
* rpc client
*
* @author Dong Liu
*/
public class RpcClient implements AutoCloseable, ServerChangedNotifier {
private final ServerProvider serverProvider;
/**
* if client want to use compress
*/
private boolean compress;
/**
* rpc call time out in milliseconds
*/
private int timeout = 10_000;
/**
* connect to rpc server timeout in milliseconds
*/
private int connectTimeout = 30_000;
/**
* extension registry for wire payload
*/
private ExtensionRegistry wpExtensionRegistry;
/**
* extension registry for rpc messages
*/
private ExtensionRegistry extensionRegistry;
private final AtomicInteger correlationId = new AtomicInteger(1);
private StubServiceFactory stubServiceFactory;
private RpcClientChannelGroup rpcClientChannelGroup;
private Bootstrap bootstrap;
private static Logger logger = LoggerFactory.getLogger(RpcClient.class);
/**
* create a rpc client
*/
public RpcClient(ServerProvider serverProvider)
throws InterruptedException, TimeoutException, IOException {
this.serverProvider = serverProvider;
this.serverProvider.setServerChangedNotifier(this);
connect();
}
/**
* connect to rpc server. could also used to reconnect when connection broken
*
* @throws IOException
*/
public void connect() throws IOException, TimeoutException, InterruptedException {
bootstrap = new Bootstrap();
bootstrap.group(new NioEventLoopGroup())
.handler(new ProtobufChannelInitializer(null, wpExtensionRegistry))
.channel(NioSocketChannel.class);
bootstrap.option(ChannelOption.TCP_NODELAY, true)
// we use connect time out for this too.
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeout)
.option(ChannelOption.SO_SNDBUF, 1_048_576)
.option(ChannelOption.SO_RCVBUF, 1_048_576);
Collection servers = serverProvider.availableServers();
if (servers == null || servers.isEmpty()) {
throw new ServiceException("no server found");
}
List channels = new ArrayList<>(servers.size());
for (ServerInfo serverInfo : servers) {
RpcClientChannel rpcClientChannel = newRpcChannel(serverInfo);
rpcClientChannel.connect();
channels.add(rpcClientChannel);
}
rpcClientChannelGroup = new RpcClientChannelGroup(channels);
stubServiceFactory = new StubServiceFactory(correlationId, this);
}
private RpcClientChannel newRpcChannel(ServerInfo serverInfo) {
return new RpcClientChannel(serverInfo, bootstrap, correlationId.getAndIncrement(),
compress, connectTimeout, Collections.emptyList(),
extensionRegistry);
}
/**
* get a rpc interface impl powered by rpc server
*
* @param interfaceClass the rpc interface class
* @param the rpc interface
* @return
*/
public T getService(Class interfaceClass) {
return stubServiceFactory.getService(interfaceClass, this.timeout);
}
/**
* get a rpc interface impl powered by rpc server with specified rpc timeout.
* the timeout will shadow the rpc time value set in rpc client
*
* @param interfaceClass the rpc interface class
* @param timeout the timeout. should larger than 0
* @param the rpc interface
* @return
*/
public T getService(Class interfaceClass, int timeout) {
return stubServiceFactory.getService(interfaceClass, timeout);
}
/**
* close rpc client
*/
@Override
public void close() {
try {
serverProvider.close();
} catch (Exception e) {
logger.error("", e);
}
// close channel
if (rpcClientChannelGroup != null) {
rpcClientChannelGroup.close();
}
try {
bootstrap.group().shutdownGracefully().sync();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
/**
* for internal use only
*/
public void writeRequest(ClientCallTask task, RpcRequest rpcRequest) {
RpcClientChannel channel = rpcClientChannelGroup.select();
channel.writeRequest(task, rpcRequest);
}
/**
* get rpc connect server timeout
*
* @return timeout in milliseconds
*/
public int getConnectTimeout() {
return connectTimeout;
}
/**
* set rpc connect server timeout. default is 10,000
*
* @param connectTimeout timeout in milliseconds. must be large than 0
* @return
*/
public RpcClient setConnectTimeout(int connectTimeout) {
if (connectTimeout <= 0) {
throw new IllegalArgumentException("Timeout should be larger than 0");
}
this.connectTimeout = connectTimeout;
return this;
}
/**
* get rpc call timeout
*
* @return timeout in milliseconds
*/
public int getTimeout() {
return timeout;
}
/**
* set time out for rpc call. default is 30,000
*
* @param timeout timeout in milliseconds. must be large than 0
*/
public void setTimeout(int timeout) {
if (timeout <= 0) {
throw new IllegalArgumentException("Timeout should be larger than 0");
}
this.timeout = timeout;
}
/**
* set if client want to use zlib compress. default is false.
* rpc will use compress if both client and server want to use compress
*/
public RpcClient setCompress(boolean compress) {
this.compress = compress;
return this;
}
/**
* if client want to use compress
*/
public boolean isCompress() {
return compress;
}
/**
* get wire payload extension registry
*/
public ExtensionRegistry getWpExtensionRegistry() {
return wpExtensionRegistry;
}
/**
* set extension registry for wire payload
*/
public RpcClient setWpExtensionRegistry(ExtensionRegistry wpExtensionRegistry) {
this.wpExtensionRegistry = wpExtensionRegistry;
return this;
}
/**
* get rpc message extension registry
*/
public ExtensionRegistry getExtensionRegistry() {
return extensionRegistry;
}
/**
* set rpc message extension registry
*/
public RpcClient setExtensionRegistry(ExtensionRegistry extensionRegistry) {
this.extensionRegistry = extensionRegistry;
return this;
}
@Override
public void notifyAdd(ServerInfo serverInfo) {
RpcClientChannel channel = newRpcChannel(serverInfo);
this.rpcClientChannelGroup.add(channel);
}
@Override
public void notifyRemove(ServerInfo serverInfo) {
this.rpcClientChannelGroup.remove(serverInfo);
}
}