我遇到了Mule ESB FTP Transport的问题:当轮询时,运行客户端的线程将无限期地挂起而不会引发错误。这会导致FTP轮询完全停止。 Mule使用Apache Commons Net FTPClient。Commons Net FTPClient无限期挂起Mule
进一步了解代码,我认为这是由于FTPClient的SocketTimeout没有被设置,有时在从FTPClient的套接字读取行时导致无限悬挂。
当问题发生时,我们可以清楚地看到用jstack检索到的堆栈中的问题。 __getReply()函数似乎是更直接的问题。
这一个挂在连接()创建一个新FTPClient时称:
receiver.172 prio=10 tid=0x00007f23e43c8800 nid=0x2d5 runnable [0x00007f24c32f1000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:152)
at java.net.SocketInputStream.read(SocketInputStream.java:122)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:283)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:325)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:177)
- locked <0x00000007817a9578> (a java.io.InputStreamReader)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:154)
at java.io.BufferedReader.readLine(BufferedReader.java:317)
- locked <0x00000007817a9578> (a java.io.InputStreamReader)
at java.io.BufferedReader.readLine(BufferedReader.java:382)
at org.apache.commons.net.ftp.FTP.__getReply(FTP.java:294)
at org.apache.commons.net.ftp.FTP._connectAction_(FTP.java:364)
at org.apache.commons.net.ftp.FTPClient._connectAction_(FTPClient.java:540)
at org.apache.commons.net.SocketClient.connect(SocketClient.java:178)
at org.mule.transport.ftp.FtpConnectionFactory.makeObject(FtpConnectionFactory.java:33)
at org.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:1188)
at org.mule.transport.ftp.FtpConnector.getFtp(FtpConnector.java:172)
at org.mule.transport.ftp.FtpConnector.createFtpClient(FtpConnector.java:637)
at org.mule.transport.ftp.FtpMessageReceiver.listFiles(FtpMessageReceiver.java:134)
at org.mule.transport.ftp.FtpMessageReceiver.poll(FtpMessageReceiver.java:94)
at org.mule.transport.AbstractPollingMessageReceiver.performPoll(AbstractPollingMessageReceiver.java:216)
at org.mule.transport.PollingReceiverWorker.poll(PollingReceiverWorker.java:80)
at org.mule.transport.PollingReceiverWorker.run(PollingReceiverWorker.java:49)
at org.mule.transport.TrackingWorkManager$TrackeableWork.run(TrackingWorkManager.java:267)
at org.mule.work.WorkerContext.run(WorkerContext.java:286)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- <0x00000007817a3540> (a java.util.concurrent.ThreadPoolExecutor$Worker)
而另挂在PASV()使用listFiles时调用():
receiver.137" prio=10 tid=0x00007f23e433b000 nid=0x7c06 runnable [0x00007f24c2fee000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:152)
at java.net.SocketInputStream.read(SocketInputStream.java:122)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:283)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:325)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:177)
- locked <0x0000000788847ed0> (a java.io.InputStreamReader)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:154)
at java.io.BufferedReader.readLine(BufferedReader.java:317)
- locked <0x0000000788847ed0> (a java.io.InputStreamReader)
at java.io.BufferedReader.readLine(BufferedReader.java:382)
at org.apache.commons.net.ftp.FTP.__getReply(FTP.java:294)
at org.apache.commons.net.ftp.FTP.sendCommand(FTP.java:490)
at org.apache.commons.net.ftp.FTP.sendCommand(FTP.java:534)
at org.apache.commons.net.ftp.FTP.sendCommand(FTP.java:583)
at org.apache.commons.net.ftp.FTP.pasv(FTP.java:882)
at org.apache.commons.net.ftp.FTPClient._openDataConnection_(FTPClient.java:497)
at org.apache.commons.net.ftp.FTPClient.initiateListParsing(FTPClient.java:2296)
at org.apache.commons.net.ftp.FTPClient.initiateListParsing(FTPClient.java:2269)
at org.apache.commons.net.ftp.FTPClient.initiateListParsing(FTPClient.java:2189)
at org.apache.commons.net.ftp.FTPClient.initiateListParsing(FTPClient.java:2132)
at org.mule.transport.ftp.FtpMessageReceiver.listFiles(FtpMessageReceiver.java:135)
at org.mule.transport.ftp.FtpMessageReceiver.poll(FtpMessageReceiver.java:94)
at org.mule.transport.AbstractPollingMessageReceiver.performPoll(AbstractPollingMessageReceiver.java:216)
at org.mule.transport.PollingReceiverWorker.poll(PollingReceiverWorker.java:80)
at org.mule.transport.PollingReceiverWorker.run(PollingReceiverWorker.java:49)
at org.mule.transport.TrackingWorkManager$TrackeableWork.run(TrackingWorkManager.java:267)
at org.mule.work.WorkerContext.run(WorkerContext.java:286)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- <0x0000000788832180> (a java.util.concurrent.ThreadPoolExecutor$Worker)
我觉得问题是由Mule默认FtpConnectionFactory中使用默认FTPClient构造函数(扩展SocketClient)引起的。
注setConnectTimeout()值似乎调用socket.connect()的时候才使用,但使用相同的插座上的其他操作忽略:
protected FTPClient createFtpClient()
{
FTPClient ftpClient = new FTPClient();
ftpClient.setConnectTimeout(connectionTimeout);
return ftpClient;
}
它使用FTPClient()构造函数,本身使用具有0超时的SocketClient,在创建套接字时定义。
public SocketClient()
{
...
_timeout_ = 0;
...
}
然后我们调用connec(),它调用_ connectAction()_。
在SocketClient:
protected void _connectAction_() throws IOException
{
...
_socket_.setSoTimeout(_timeout_);
...
}
在FTP,一个新的阅读器实例化以后,我们永远插座:
protected _connectAction_(){
...
_controlInput_ =
new BufferedReader(new InputStreamReader(_socket_.getInputStream(),
getControlEncoding()));
...
}
然后调用__getReply()函数时,我们使用这个阅读器,与 - 永久插座:
private void __getReply() throws IOException
{
...
String line = _controlInput_.readLine();
...
}
对不起,很长的文章,但我认为这需要正确的解释秒。解决方案可能是在connect()之后调用setSoTimeout()来定义套接字超时。
有一个默认超时似乎不是一个可接受的解决方案,因为每个用户可能有不同的需求,并且在任何情况下默认不适合。 https://issues.apache.org/jira/browse/NET-35
最后,提出了2个问题:
- 这似乎是我的错误,因为它会完全停止FTP轮询不给错误。你怎么看?
- 什么可以是一种简单的方法来避免这种情况?用自定义的FtpConnectionFactory调用setSoTimeout()?我在某处丢失配置或参数吗?
提前致谢。
编辑:我使用Mule CE Standalone 3.5.0,它似乎使用Apache Commons Net 2.0。但在代码中看来,Mule CE Standalone 3.7与Commons Net 2.2似乎并不相同。下面是源代码涉及:
你好维克多,我也试图提出一个bug昨天但注册页面似乎目前不可用(给我一个404)。如果它仍然存在,我会尝试联系管理员。 ResponseTimeout被设置为10000,这并不妨碍该问题。我目前使用[MockFtp](http://mockftpserver.sourceforge.net/)重现并尝试自定义FtpConnectionFactory。重写接收器似乎也是一个好主意,谢谢! –
我试图用自定义的messageReceiver(FtpMessageReceiver)来使用服务覆盖,看起来FTP客户端的创建是在这个类的多个地方完成的。这需要创建一个新客户端的任何函数都可以通过调用来重写,以便每次都设置超时值。但是,由于每个客户端创建调用都源自FtpConnectionFactory,我认为应该可以重写此代替。 –