<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> I have searched the <a href="https://github.com/apache/dubbo/issues">issues</a> of this repository and believe that this is not a duplicate.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> I have checked the <a href="https://github.com/apache/dubbo/blob/master/FAQ.md">FAQ</a> of this repository and believe that this is not a duplicate.</li>
</ul>
<h3 dir="auto">Environment</h3>
<ul dir="auto">
<li>Dubbo version: 2.7.6</li>
<li>Operating System version: win10 x64</li>
<li>Java version: 1.8</li>
</ul>
<h3 dir="auto">Steps to reproduce this issue</h3>
<ol dir="auto">
<li>dubbo从2.8.4 的版本升级到2.7.6的版本，生产者启动正常，消费者调用多个应用的生产实例化dubbo的bean时抛出异常。 低版本启动正常，使用正常。</li>
</ol>
<p dir="auto">Pls. provide [GitHub address] to reproduce this issue.</p>
<h3 dir="auto">Expected Result</h3>
<p dir="auto">What do you expected from the above steps？</p>
<h3 dir="auto">Actual Result</h3>
<p dir="auto">What actually happens?</p>
<p dir="auto">If there is an exception, please attach the exception trace:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="堆栈异常如下：
[stack trace.txt](https://github.com/apache/dubbo/files/4786508/stack.trace.txt)

"><pre class="notranslate"><code class="notranslate">堆栈异常如下：
[stack trace.txt](https://github.com/apache/dubbo/files/4786508/stack.trace.txt)


</code></pre></div>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I have searched the <a href="https://github.com/apache/dubbo/issues">issues</a> of this repository and believe that this is not a duplicate.</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I have checked the <a href="https://github.com/apache/dubbo/blob/master/FAQ.md">FAQ</a> of this repository and believe that this is not a duplicate.</li>
</ul>
<h3 dir="auto">Environment</h3>
<ul dir="auto">
<li>Dubbo version: 2.7.6</li>
<li>Operating System version: linux/windows</li>
<li>Java version: 1.8</li>
</ul>
<p dir="auto">简述一下问题<br>
启动一个consumer和一个provider<br>
在consumer中重复调用一个provider n次(执行时间长一点容易发现)<br>
这时向consumer发送kill -15 命令<br>
可能会报错:<br>
<code class="notranslate">org.apache.dubbo.rpc.RpcException: Failed to invoke the method sayHello in the service com.dubbo.springboot.demo.provider.service.DemoService. Tried 3 times of the providers [x.x.x.x:xxxx] (1/1) from the registry localhost:2181 on the consumer x.x.x.x using the dubbo version 2.7.6. Last error is: Failed to invoke remote method: sayHello, provider......</code><br>
导致程序提前中断</p>
<h3 dir="auto">Steps to reproduce this issue</h3>
<ol dir="auto">
<li>provider service<br>
`<br>
package org.apache.dubbo.spring.boot.sample.provider.service;</li>
</ol>
<p dir="auto">import org.apache.dubbo.config.annotation.Service;<br>
import org.springframework.beans.factory.annotation.Value;</p>
<p dir="auto">import com.dubbo.springboot.demo.provider.service.DemoService;</p>
<p dir="auto">/**</p>
<ul dir="auto">
<li>
<p dir="auto">Default {<a class="user-mention notranslate" data-hovercard-type="organization" data-hovercard-url="/orgs/link/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/link">@link</a> DemoService}</p>
</li>
<li>
</li><li>
<p dir="auto"><a class="user-mention notranslate" data-hovercard-type="organization" data-hovercard-url="/orgs/see/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/see">@see</a> DemoService</p>
</li>
<li>
<p dir="auto"><a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/SInCE/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/SInCE">@SInCE</a> 2.7.0<br>
*/<br>
<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/service/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/service">@service</a>(version = "${demo.service.version}", timeout = 30000)<br>
public class DefaultDemoService implements DemoService {</p>
<p dir="auto">/**</p>
<ul dir="auto">
<li>The default value of ${dubbo.application.name} is ${spring.application.name}<br>
*/<br>
<a class="user-mention notranslate" data-hovercard-type="organization" data-hovercard-url="/orgs/value/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/value">@value</a>("${dubbo.application.name}")<br>
private String serviceName;</li>
</ul>
<p dir="auto">// <a class="user-mention notranslate" data-hovercard-type="organization" data-hovercard-url="/orgs/resource/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/resource">@resource</a><br>
// private KafkaTemplate&lt;String, Object&gt; kafkaTemplate;</p>
<p dir="auto"><a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/OverRide/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/OverRide">@OverRide</a><br>
public String sayHello(String name) {<br>
try {<br>
Thread.sleep(1000);<br>
} catch (InterruptedException e) {<br>
e.printStackTrace();<br>
}<br>
System.out.println("sayHello");<br>
return String.format("[%s] : Hello, %s", serviceName, name);<br>
}<br>
}<br>
`</p>
</li>
</ul>
<ol start="2" dir="auto">
<li>consumer service<br>
`<br>
package com.dubbo.springboot.demo.consumer.service;</li>
</ol>
<p dir="auto">import org.apache.dubbo.config.annotation.Reference;<br>
import org.springframework.stereotype.Service;</p>
<p dir="auto">import com.dubbo.springboot.demo.provider.service.DemoService;</p>
<p dir="auto"><a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/service/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/service">@service</a><br>
public class DemoConsumerService {</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="@Reference(version = &quot;${demo.service.version}&quot;)
private DemoService demoService;

public String sayHello(String name) {
	for (int i = 0; i &lt; 10; i++) {
		try {
			demoService.sayHello(name);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	return &quot;nb&quot;;
}"><pre class="notranslate"><code class="notranslate">@Reference(version = "${demo.service.version}")
private DemoService demoService;

public String sayHello(String name) {
	for (int i = 0; i &lt; 10; i++) {
		try {
			demoService.sayHello(name);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	return "nb";
}
</code></pre></div>
<p dir="auto">}<br>
`</p>
<ol start="3" dir="auto">
<li>cause<br>
`</li>
</ol>
<ol dir="auto">
<li>
<p dir="auto">org.apache.dubbo.remoting.exchange.support.DefaultFuture ==&gt; 184行<br>
private static final Map&lt;Long, Channel&gt; CHANNELS = new ConcurrentHashMap&lt;&gt;();<br>
public static void received(Channel channel, Response response, boolean timeout) {<br>
try {<br>
DefaultFuture future = FUTURES.remove(response.getId());<br>
if (future != null) {<br>
Timeout t = future.timeoutCheckTask;<br>
if (!timeout) {<br>
// decrease Time<br>
t.cancel();<br>
}<br>
future.doReceived(response);<br>
} else {<br>
logger.warn("The timeout response finally returned at "<br>
+ (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()))<br>
+ ", response " + response<br>
+ (channel == null ? "" : ", channel: " + channel.getLocalAddress()<br>
+ " -&gt; " + channel.getRemoteAddress()));<br>
}<br>
} finally {<br>
CHANNELS.remove(response.getId());//  &lt;== 这里会把channel删掉<br>
}<br>
}</p>
</li>
<li>
<p dir="auto">org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeChannel ==&gt; 168行<br>
private volatile boolean closed = false;<br>
public void close(int timeout) {<br>
if (closed) {<br>
return;<br>
}<br>
closed = true; // &lt;== 这里会导致在下面循环进行时,其他请求进不来,<br>
if (timeout &gt; 0) {<br>
long start = System.currentTimeMillis();<br>
while (DefaultFuture.hasFuture(channel) // &lt;== 因为1的原因这里会返回false<br>
&amp;&amp; System.currentTimeMillis() - start &lt; timeout) {<br>
try {<br>
Thread.sleep(10); // &lt;==可能存在10ms,channle已经从1中的CHANNELS里remove掉了,但是没有被close掉,导致下一次请求时closed还是true,而不是新创建一个channel,导致4出现问题<br>
} catch (InterruptedException e) {<br>
logger.warn(e.getMessage(), e);<br>
}<br>
}<br>
}<br>
close();<br>
}</p>
</li>
<li>
<p dir="auto">org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeChannel ==&gt; 93行<br>
public void send(Object message, boolean sent) throws RemotingException {<br>
if (closed) {<br>
throw new RemotingException(this.getLocalAddress(), null, "Failed to send message " + message + ", cause: The channel " + this + " is closed!"); // &lt;== 这里会因为2的原因报错<br>
}<br>
if (message instanceof Request<br>
|| message instanceof Response<br>
|| message instanceof String) {<br>
channel.send(message, sent);<br>
} else {<br>
Request request = new Request();<br>
request.setVersion(Version.getProtocolVersion());<br>
request.setTwoWay(false);<br>
request.setData(message);<br>
channel.send(request, sent);<br>
}<br>
}</p>
</li>
<li>
<p dir="auto">org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeChannel ==&gt; 63行<br>
static HeaderExchangeChannel getOrAddChannel(Channel ch) {<br>
if (ch == null) {<br>
return null;<br>
}<br>
HeaderExchangeChannel ret = (HeaderExchangeChannel) ch.getAttribute(CHANNEL_KEY); // 因为channle没有被关闭,这里能取到ret而不是重新创建channle<br>
if (ret == null) {<br>
ret = new HeaderExchangeChannel(ch);<br>
if (ch.isConnected()) {<br>
ch.setAttribute(CHANNEL_KEY, ret);<br>
}<br>
}<br>
return ret;<br>
}<br>
`</p>
</li>
</ol>
<ol start="4" dir="auto">
<li></li>
</ol>
<p dir="auto">出现这种问题的原因:<br>
DefaultFuture 中有 CHANNELS ,在每次初始化 DefaultFuture 的时候会向里面添加数据<br>
有用在 HeaderExchangeChannel中 close(int timeout)  DefaultFuture.hasFuture(channel)<br>
这里有一个循环,每隔10ms判断 CHANNELS 中是否还存在当前的 channel ,如果不存在则关闭当前channel,<br>
这就导致可能会存在10ms的误差,期间 CHANNELS 中已经没有了当前channel,但是当前channel并未关闭,closed = true,<br>
进而导致下一次调用该provider时,closed=true,在HeaderExchangeChannel 93行会抛出异常<br>
原本的逻辑应该是HeaderExchangeChannel 的 63行,当rat不存在的时候 创建一个HeaderExchangeChannel 进行通信.</p>
<p dir="auto">个人技术有限,现在没有完善的解决方案,希望各位大佬能解决一下</p>
<p dir="auto">第一次写的乱、草率还请见谅</p>