WSO2 ESB 4.9.0 JMS生产者故障转移传输超时配置问题
我正在使用WSO2 ESB 4.9.0,想要通过HTTP API把消息推送到ActiveMQ的JMS队列中。JMS发送需要用到故障转移机制,当所有ActiveMQ broker都不可用时,希望在15秒超时后执行faultsequence,给原始客户端返回HTTP 500错误码和JSON格式的响应。
我尝试过两种配置方式:
- 在ActiveMQ连接工厂里配置URL:
<parameter name="java.naming.provider.url" locked="false">failover:(tcp://localhost:61616)?timeout=3000</parameter>
- 在api.xml的endpoint URI里设置timeout参数:
<send> <endpoint> <address uri="jms:/MyQueue?java.naming.provider.url=failover:(tcp://localhost:616161)?timeout=3000"/> </endpoint> </send>
但当我关闭所有ActiveMQ broker后,API会无限阻塞,比如用curl请求时必须手动终止,完全没返回预期的错误:
curl -XPOST -H "Content-Type: application/json" -d '{}' -k "https://localhost:8243/myApi/send" ^C # 手动终止
根据ActiveMQ故障转移传输的说明:
默认情况下,当broker不可用时,故障转移传输下的发送操作会无限阻塞。有两种方案可处理此场景:一是直接在ActiveMQConnectionFactory上设置TransportListener,确保其在任何可能需要网络跳转的请求之前就位;二是设置timeout选项。timeout选项会使当前发送操作在指定超时后失败。
示例:failover:(tcp://primary:61616)?timeout=3000
在此示例中,如果未建立连接,发送操作将在3秒后超时。需要注意的是,超时发生时连接不会被关闭。因此,当broker恢复可用后,仍可使用同一连接重新发送受影响的消息。
请问该如何在WSO2 ESB中实现这个需求?
解决方法
我来帮你搞定这个问题,你遇到的核心问题是只配置了ActiveMQ的故障转移超时,但没给WSO2 ESB的发送操作设置超时触发逻辑,导致ESB一直阻塞等待。另外你第二个配置里的端口写错了(616161应该是61616),这个小错误也会干扰预期的超时触发。下面是具体的分步配置方案:
1. 正确配置ActiveMQ连接工厂
推荐在WSO2 EI管理控制台的Transport Configurations > JMS Sender里修改,或者直接编辑repository/conf/axis2/axis2.xml文件,配置故障转移URL、超时和重连策略:
<transportSender name="jms" class="org.apache.axis2.transport.jms.JMSSender"> <parameter name="default" locked="false"> <parameter name="java.naming.factory.initial" locked="false">org.apache.activemq.jndi.ActiveMQInitialContextFactory</parameter> <!-- 设置15秒超时,同时关闭重连尝试,更快触发超时 --> <parameter name="java.naming.provider.url" locked="false">failover:(tcp://localhost:61616)?timeout=15000&maxReconnectAttempts=0</parameter> <parameter name="transport.jms.ConnectionFactoryJNDIName" locked="false">QueueConnectionFactory</parameter> <parameter name="transport.jms.ConnectionFactoryType" locked="false">queue</parameter> </parameter> </transportSender>
这里maxReconnectAttempts=0的作用是让ActiveMQ不尝试重连,直接在超时后抛出错误,避免额外的等待时间。
2. 在API中配置带超时的Endpoint和故障序列
在你的API定义里,必须给endpoint设置ESB层面的发送超时,同时绑定faultsequence来处理错误响应:
<api xmlns="http://ws.apache.org/ns/synapse" name="myApi" context="/myApi"> <resource methods="POST" uri-template="/send"> <inSequence> <send> <endpoint name="JMSQueueEndpoint"> <address uri="jms:/MyQueue?transport.jms.ConnectionFactoryType=queue"> <!-- 配置ESB发送超时,和ActiveMQ的timeout保持一致 --> <timeout> <duration>15000</duration> <responseAction>fault</responseAction> </timeout> <!-- 捕获所有错误,包括连接超时 --> <suspendOnFailure> <errorCodes>-1</errorCodes> <initialDuration>0</initialDuration> <progressionFactor>1.0</progressionFactor> <maximumDuration>0</maximumDuration> </suspendOnFailure> </address> </endpoint> </send> <respond/> </inSequence> <!-- 故障序列:返回HTTP 500和JSON错误 --> <faultSequence> <!-- 设置HTTP状态码为500 --> <property name="HTTP_SC" value="500" scope="axis2"/> <!-- 构建自定义JSON错误响应 --> <payloadFactory media-type="json"> <format>{"error": "Failed to send message to ActiveMQ", "reason": "$1"}</format> <args> <arg evaluator="xml" expression="get-property('ERROR_MESSAGE')"/> </args> </payloadFactory> <!-- 将响应返回给原始客户端 --> <respond/> </faultSequence> </resource> </api>
这里的关键配置点:
<timeout>标签的duration要和ActiveMQ的timeout匹配,responseAction=fault表示超时后直接进入faultsequence。<suspendOnFailure>里的errorCodes=-1表示捕获所有类型的错误,确保连接超时能被正确触发。
3. 验证效果
关闭所有ActiveMQ broker后,用curl请求你的API:
curl -XPOST -H "Content-Type: application/json" -d '{}' -k "https://localhost:8243/myApi/send"
等待15秒后,你会收到类似这样的JSON响应,同时HTTP状态码为500:
{"error": "Failed to send message to ActiveMQ", "reason": "Error sending message to JMS destination; nested exception is javax.jms.JMSException: Could not connect to broker URL: failover:(tcp://localhost:61616). Reason: java.net.ConnectException: Connection refused"}
补充说明
你之前的配置没生效的原因:
- 只配置了ActiveMQ的timeout,但WSO2 ESB的
send操作默认没有超时限制,所以即使ActiveMQ触发了超时,ESB还是会一直等待。必须通过endpoint的<timeout>配置来让ESB在指定时间后触发故障处理。 - 第二个配置里的端口错误(616161)会导致连接失败,但如果没有ESB的超时配置,还是会无限阻塞。
内容的提问来源于stack exchange,提问作者jonenst

