xuxueli / xxl-job

A distributed task scheduling framework.(分布式任务调度平台XXL-JOB)
http://www.xuxueli.com/xxl-job/
GNU General Public License v3.0
27.59k stars 10.92k forks source link

xxl-rpc response data empty.(go语言适配2.1.2版本调度器问题) #2592

Closed youbeiwuhuan closed 3 years ago

youbeiwuhuan commented 3 years ago

问题背景:适配go语言执行器,已完成2.3.0的适配,现在适配2.1.2。(代码链接:https://gitee.com/youbeiwuhuan/go-xxljob-executor/tree/dev2.1.2/

问题描述: 点击后台执行一次任务,执行器端用gin+dubbo-go-hessian2 能正常接收并解析出xxl-rpc发送的得XxlRpcRequest对象,但向调度器返回XxlRpcResponse时,后台报如下错误:

11:20:52.417 logback [nioEventLoopGroup-3-1] ERROR c.x.r.r.n.i.n.c.NettyHttpClientHandler - >>>>>>>>>>> xxl-rpc netty_http client caught exception com.xxl.rpc.util.XxlRpcException: xxl-rpc response data empty. at com.xxl.rpc.remoting.net.impl.netty_http.client.NettyHttpClientHandler.channelRead0(NettyHttpClientHandler.java:48) at com.xxl.rpc.remoting.net.impl.netty_http.client.NettyHttpClientHandler.channelRead0(NettyHttpClientHandler.java:22) at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:438) at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:326) at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:300) at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:253) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:287) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1422) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:931) at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:700) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:635) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:552) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:514) at io.netty.util.concurrent.SingleThreadEventExecutor$6.run(SingleThreadEventExecutor.java:1050) at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.lang.Thread.run(Thread.java:748)

报错很明显是不能解析出XxlRpcResponse的data字段,现在已通过代码实验确认dubbo-go-hessian2与xxl-rpc的hessian2是兼容的。推测原因在返回的http报文的结构上不符合xxl-rpc要求。希望大佬能告诉我xxl-rpc的报文格式要求(自己没有从xxl-rpc源码找到答案)。我实验中用tcp-mon抓到的报文如下:

-----------------------调度器发给go执行器的报文(执行器能正常解析)---------------------------------- POST / HTTP/1.1 host: 127.0.0.1 connection: keep-alive content-length: 589

C0-com.xxl.rpc.remoting.net.params.XxlRpcRequest� requestIdcreateMillisTime accessToken className methodNameversionparameterTypes parameters`0$ce3f986c-97d0-4376-94b8-6276b4b5ed88L


-----------------------执行器回应调度器的报文(调度器报上面异常)---------------------------------- HTTP/1.1 200 OK Connection: keep-alive Content-Length: 176 Content-Type: text/html;charset=UTF-8 Date: Thu, 09 Sep 2021 03:20:22 GMT

C0.com.xxl.rpc.remoting.net.params.XxlRpcResponse� requestIderrorMsgresult`0$ce3f986c-97d0-4376-94b8-6276b4b5ed88


youbeiwuhuan commented 3 years ago

原因已找到,问题在另外一个地方: XxlRpcReferrenceBean.java 241行

XxlRpcResponse xxlRpcResponse = futureResponse.get(timeout, TimeUnit.MILLISECONDS); if (xxlRpcResponse.getErrorMsg() != null) { throw new XxlRpcException(xxlRpcResponse.getErrorMsg()); } return xxlRpcResponse.getResult();

这里判断xxlRpcResponse.getErrorMsg() != null,而go语言的ErrorMsg 为string类型,string类型的零值为“”(空字符串),不是nil,转化为java对象则是空字符串导致这里异常,所以读不到返回数据,并非协议报文出问题。