Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.0] NPE when consumer invoke timeout #8362

Closed
2 tasks done
zhangyz-hd opened this issue Jul 28, 2021 · 2 comments
Closed
2 tasks done

[3.0] NPE when consumer invoke timeout #8362

zhangyz-hd opened this issue Jul 28, 2021 · 2 comments
Labels
type/bug Bugs to being fixed

Comments

@zhangyz-hd
Copy link
Contributor

  • I have searched the issues of this repository and believe that this is not a duplicate.
  • I have checked the FAQ of this repository and believe that this is not a duplicate.

Environment

  • Dubbo version: 3.0.2-SNAPSHOT
  • Operating System version: ANY
  • Java version: 8

Steps to reproduce this issue

服务调用timeout时,消费者端出现NPE日志

java.lang.NullPointerException
	at org.apache.dubbo.rpc.protocol.dubbo.DecodeableRpcResult.decode(DecodeableRpcResult.java:122)
	at org.apache.dubbo.remoting.transport.DecodeHandler.decode(DecodeHandler.java:57)
	at org.apache.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:48)
	at org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.java:57)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at org.apache.dubbo.common.threadlocal.InternalRunnable.run(InternalRunnable.java:41)
	at java.lang.Thread.run(Thread.java:748)

代码位置

    public void decode() throws Exception {
        if (!hasDecoded && channel != null && inputStream != null) {
            try {
                if (ConfigurationUtils.getSystemConfiguration().getBoolean(SERIALIZATION_SECURITY_CHECK_KEY, true)) {
                    Object serializationType_obj = invocation.get(SERIALIZATION_ID_KEY); // <------ invocation IS NULL!!
                    if (serializationType_obj != null) {
                        if ((byte) serializationType_obj != serializationType) {
                            throw new IOException("Unexpected serialization id:" + serializationType + " received from network, please check if the peer send the right id.");
                        }
                    }
                }
                decode(channel, inputStream);
            } catch (Throwable e) {

初步分析原因

超时时,消费者端TimeoutCheckTask创建了timeoutResponse,并调用了DefaultFuture.received

        private void notifyTimeout(DefaultFuture future) {
            // create exception response.
            Response timeoutResponse = new Response(future.getId());
            // set timeout status.
            timeoutResponse.setStatus(future.isSent() ? Response.SERVER_TIMEOUT : Response.CLIENT_TIMEOUT);
            timeoutResponse.setErrorMessage(future.getTimeoutMessage(true));
            // handle response.
            DefaultFuture.received(future.getChannel(), timeoutResponse, true);
        }

DefaultFuture.received内会先从FUTURES中删除该id

    public static void received(Channel channel, Response response, boolean timeout) {
        try {
            DefaultFuture future = FUTURES.remove(response.getId());
            if (future != null) {
                Timeout t = future.timeoutCheckTask;
                if (!timeout) {

当服务提供者返回调用结果时,DefaultFuture#FUTURES缓存的id已经被删除,从而导致DubboCodec#decodeBody中创建DecodeableRpcResult时,传入的invocation是null

// org.apache.dubbo.rpc.protocol.dubbo.DubboCodec#decodeBody
                        if (channel.getUrl().getParameter(DECODE_IN_IO_THREAD_KEY, DEFAULT_DECODE_IN_IO_THREAD)) {
                            result = new DecodeableRpcResult(channel, res, is,
                                    (Invocation) getRequestData(id), proto);
                            result.decode();
                        } else {
                            result = new DecodeableRpcResult(channel, res,
                                    new UnsafeByteArrayInputStream(readMessageData(is)),
                                    (Invocation) getRequestData(id), proto);
                        }
// org.apache.dubbo.remoting.exchange.codec.ExchangeCodec#getRequestData
    protected Object getRequestData(long id) {
        DefaultFuture future = DefaultFuture.getFuture(id);
        if (future == null) {
            return null;    //<----------(^_^)v
        }
        Request req = future.getRequest();
        if (req == null) {
            return null;
        }
        return req.getData();
    }
@AlbumenJ AlbumenJ added the type/bug Bugs to being fixed label Jul 30, 2021
@wangchengming666
Copy link
Member

I'll try to fix it.

@CrazyHZM
Copy link
Member

Resolved in #8587

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type/bug Bugs to being fixed
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants