motan
motan copied to clipboard
异步回调里再调rpc接口问题
循环异步调用接口,在异步调用接口的回调里再次调用rpc接口,会抛出com.weibo.api.motan.exception.MotanServiceException: error_message: NettyChannel send request to server Error
找了很久,发现这是由于回调线程是netty的nioEventLoopGroup线程,而再次调用rpc接口也是用这个线程,导致了netty的ChannelFuture.awaitUninterruptibly()=false,是我写法不对,还是本来就有这个问题 我想到的解决方法:用另一个线程去执行回调 代码:
static void async(TestServiceAsync serviceAsync) {
try {
for (int i = 0; i < 10; i++ ) {
ResponseFuture future = serviceAsync.getUserAsync(1);
future.addListener(new FutureListener() {
@Override
public void operationComplete(Future future) {
User user = (User) future.getValue();
user.setId(2);
serviceAsync.updateUserAsync(user);
}
});
}
} catch (Exception e) {
e.printStackTrace();
}
}
com.weibo.api.motan.exception.MotanServiceException: error_message: NettyChannel send request to server Error: url=motan://192.168.10.80:8002/test.service.TestService local=/192.168.10.80:65078 requestId=1630936993823195139 interface=test.service.TestService method=getUser(int), status: 503, error_code: 10001,r=null
at com.weibo.api.motan.transport.netty4.NettyChannel.request(NettyChannel.java:91)
at com.weibo.api.motan.transport.netty4.NettyClient.request(NettyClient.java:111)
at com.weibo.api.motan.transport.netty4.NettyClient.request(NettyClient.java:76)
at com.weibo.api.motan.protocol.rpc.DefaultRpcReferer.doCall(DefaultRpcReferer.java:52)
at com.weibo.api.motan.rpc.AbstractReferer.call(AbstractReferer.java:64)
at com.weibo.api.motan.cluster.ha.FailoverHaStrategy.call(FailoverHaStrategy.java:74)
at com.weibo.api.motan.cluster.support.ClusterSpi.call(ClusterSpi.java:73)
at com.weibo.api.motan.proxy.AbstractRefererHandler.invokeRequest(AbstractRefererHandler.java:77)
at com.weibo.api.motan.proxy.RefererInvocationHandler.invoke(RefererInvocationHandler.java:72)
at com.sun.proxy.$Proxy12.getUserAsync(Unknown Source)
at test.ClientApplicationXML.async(ClientApplicationXML.java:38)
at test.ClientApplicationXML.main(ClientApplicationXML.java:21)
Caused by: java.util.concurrent.CancellationException
at io.netty.util.concurrent.DefaultPromise.cancel(...)(Unknown Source)
建议在你实现的FutureListener中使用独立线程池进行异步调用,netty io线程数量有限,只适合做一些简单操作,不宜进行远程调用等重量级的操作
为什么官方不自己写一个独立的线程池来回调,这是我的
public class AsyncCaller {
static ExecutorService executorService = Executors.newFixedThreadPool(10);
public static void call(final Callable callable) {
call(callable, null);
}
public static void call(final Callable<ResponseFuture> callable, final AsyncResponseListener listener) {
try {
ResponseFuture future = callable.call();
future.addListener(new FutureListener() {
@Override
public void operationComplete(Future future) {
if (future.isSuccess() && future.isDone()) {
if (listener != null) {
executorService.submit(() -> listener.onSucc(future.getValue()));
}
return;
} else {
if ((future.getException() != null)) {
Exception e = future.getException();
log.error("motan async call " + callable.toString() + "error:", e);
}
if (listener != null) {
executorService.submit(() -> listener.onFail());
}
}
}
});
} catch (Exception e) {
log.error("motan async call " + callable.toString() + "error:", e);
}
}
}
这个比较偏业务,因此只提供了接口,没有考虑提供具体实现类
嗯,估计之前有几个人报这个错误,如果排除网络原因,也是这个问题