Java WSO2ESB 4.8.1 PassThroughHttpSender不会在异常时将线程返回到工作线程池
我认为org.apache.synapse.transport.passthru.PassThroughHttpSender是wso2esb 4.8.1中http的默认传输发送器(不确定4.9.0稍后是否会检查它),在某些情况下不会在异常时将借用的线程返回到工作线程池 在我看来,当异常在外部序列中发生时(而不是在直接接受传入请求的代理中),就会发生这种情况。例如,当您使用存储和消息处理器实现存储转发模式时,就会发生这种情况 这是我的简单WSO2ESB 4.8.1配置,用于重现该问题:Java WSO2ESB 4.8.1 PassThroughHttpSender不会在异常时将线程返回到工作线程池,java,multithreading,thread-safety,wso2esb,endpoint,Java,Multithreading,Thread Safety,Wso2esb,Endpoint,我认为org.apache.synapse.transport.passthru.PassThroughHttpSender是wso2esb 4.8.1中http的默认传输发送器(不确定4.9.0稍后是否会检查它),在某些情况下不会在异常时将借用的线程返回到工作线程池 在我看来,当异常在外部序列中发生时(而不是在直接接受传入请求的代理中),就会发生这种情况。例如,当您使用存储和消息处理器实现存储转发模式时,就会发生这种情况 这是我的简单WSO2ESB 4.8.1配置,用于重现该问题: <?
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://ws.apache.org/ns/synapse">
<registry provider="org.wso2.carbon.mediation.registry.WSO2Registry">
<parameter name="cachableDuration">15000</parameter>
</registry>
<import name="fileconnector"
package="org.wso2.carbon.connector"
status="enabled"/>
<proxy name="ProxyTest"
transports="http https"
startOnLoad="true"
trace="disable">
<target>
<inSequence>
<property name="FORCE_SC_ACCEPTED"
value="true"
scope="axis2"
type="STRING"/>
<log level="custom">
<property name="text" value="store message"/>
</log>
<store messageStore="TestXMS"/>
<log level="custom">
<property name="text" value="message stored"/>
</log>
</inSequence>
<outSequence/>
<faultSequence/>
</target>
</proxy>
<localEntry key="ESBInstance">Test<description/>
</localEntry>
<endpoint name="HTTPEndpoint">
<http method="post" uri-template="http://localhost/index.php">
<timeout>
<duration>10</duration>
<responseAction>fault</responseAction>
</timeout>
<suspendOnFailure>
<errorCodes>-1</errorCodes>
<initialDuration>0</initialDuration>
<progressionFactor>1.0</progressionFactor>
<maximumDuration>0</maximumDuration>
</suspendOnFailure>
<markForSuspension>
<errorCodes>-1</errorCodes>
</markForSuspension>
</http>
</endpoint>
<sequence name="fault">
<log level="full">
<property name="MESSAGE" value="Executing default 'fault' sequence"/>
<property name="ERROR_CODE" expression="get-property('ERROR_CODE')"/>
<property name="ERROR_MESSAGE" expression="get-property('ERROR_MESSAGE')"/>
</log>
<drop/>
</sequence>
<sequence name="TestSequence">
<log level="full">
<property name="text" value="message recieved"/>
</log>
<call>
<endpoint key="HTTPEndpoint"/>
</call>
<log level="full">
<property name="text" value="message processed"/>
</log>
</sequence>
<sequence name="main">
<in>
<log level="full"/>
<filter source="get-property('To')" regex="http://localhost:9000.*">
<send/>
</filter>
</in>
<out>
<send/>
</out>
<description>The main sequence for the message mediation</description>
</sequence>
<messageStore name="TestXMS"/>
<messageProcessor class="org.apache.synapse.message.processor.impl.sampler.SamplingProcessor"
name="TestMP"
messageStore="TestXMS">
<parameter name="interval">1000</parameter>
<parameter name="sequence">TestSequence</parameter>
<parameter name="concurrency">1</parameter>
<parameter name="is.active">true</parameter>
</messageProcessor>
</definitions>
这是进程堆栈出错的地方。当异常发生(在另一个线程中)时,它“忘记”通知当前线程,而msgContext将永远等待(实际上直到服务器重新启动)
所以我稍微修改了同一个包中的另一个类-DeliveryAgent,MethodErrorConnection。此方法用于捕获来自用于连接到目标主机的线程的回调。。。因此,当我们捕获回调时,我们会通知msgContext并通过在targetErrorHandler之后添加新的同步块来通知它继续
public void errorConnecting(HttpRoute route, int errorCode, String message)
{
Queue<MessageContext> queue = (Queue)this.waitingMessages.get(route);
if (queue != null)
{
MessageContext msgCtx = (MessageContext)queue.poll();
if (msgCtx != null) {
this.targetErrorHandler.handleError(msgCtx, errorCode, "Error connecting to the back end", null, ProtocolState.REQUEST_READY);
synchronized (msgCtx)
{
log.info("errorConnecting: notify message context about error");
msgCtx.setProperty("PASSTHRU_CONNECT_ERROR", Boolean.TRUE);
msgCtx.notifyAll();
}
}
}
else
{
throw new IllegalStateException("Queue cannot be null for: " + route);
}
}
public void errorConnecting(HttpRoute路由、int errorCode、字符串消息)
{
Queue Queue=(Queue)this.waitingMessages.get(route);
if(队列!=null)
{
MessageContext msgCtx=(MessageContext)queue.poll();
如果(msgCtx!=null){
this.targetErrorHandler.handleError(msgCtx,错误代码,“连接后端时出错”,null,ProtocolState.REQUEST\u READY);
已同步(msgCtx)
{
info(“errorConnecting:notifymessagecontext关于错误”);
msgCtx.setProperty(“PASSTHRU\u CONNECT\u ERROR”,Boolean.TRUE);
msgCtx.notifyAll();
}
}
}
其他的
{
抛出新的IllegalStateException(“对于:+路由,队列不能为null”);
}
}
我做了一些测试,看起来它解决了“死”线程的问题。然而,我不确定这是否是一个适当的修复或不。。。欢迎提出任何建议
链接到反编译和修改的源文件-我找到了问题的原因。如果后端应用程序接受请求并且不向ESB回复任何内容,就会发生这种情况。结果,连接因超时而关闭。在这种情况下,ESB工作线程不会返回到线程池 为了克服这个问题,需要修补org.apache.synapse.transport.passthru.TargetErrorHandler java类
synchronized (mc){
log.info("notify message context about error");
mc.setProperty("PASSTHRU_CONNECT_ERROR", Boolean.TRUE);
mc.notifyAll();
}
把它放在挡块前面
它将正确地将消息上下文设置为有错误,并通知所有等待的对象,从而允许ESB返回线程池中的请求处理线程。所有这些对于4.8.1都是正确的
我已经对其进行了修补,并将其置于生产环境中,该环境在2016年1月每天处理数百万个请求。从那时起就没有问题了
synchronized (mc){
log.info("notify message context about error");
mc.setProperty("PASSTHRU_CONNECT_ERROR", Boolean.TRUE);
mc.notifyAll();
}