BlazeDS + ActiveMQ:Flex客户端与持久主题的非正常断开连接不会将其从ActiveMQ中删除

时间:2011-07-02 21:37:14

标签: flex activemq blazeds

我正在尝试使用BlazeDS的JMS桥,使基于Flex的桌面应用程序使用持久订阅来使用来自ActiveMQ主题的消息。基本情况如下:

  1. 消息由Flex客户端订阅的主题中的其他制作者生成。

  2. Flex客户端可能会不时脱机,但是当它再次连接到BlazeDS时,它必须在脱机时收到它已经丢失的所有消息。 (当然,Flex客户端每次都使用相同的客户端ID连接。)

  3. 可以保证Flex客户端正常关闭。

  4. 如果我通过调用disconnect()在Flex端明确地断开我的消费者的连接,一切正常。 - 我在应用程序的退出处理程序中执行此操作。但是,由于上面的#3,无法保证始终调用disconnect()。当Flex客户端在不调用disconnect()的情况下关闭时,BlazeDS创建并关联到Flex客户端的“代理JMS客户端”的订阅似乎对ActiveMQ保持活动状态,因此ActiveMQ仍然认为客户端已登录.Flex应用程序下次启动时,无法登录BlazeDS,因为ActiveMQ拒绝其订阅,声称客户端ID已被占用。为什么会这样,我该怎么做才能确保BlazeDS在ActiveMQ中使“代理JMS客户端”脱机,而其真正的Flex对应物意外终止?

    更详细的信息:一些调试显示:

    1. BlazeDS意识到Flex客户端已终止,因为它在调试模式下会向控制台输出一些例外情况。消息如下:

      [BlazeDS]23:18:13.688 [WARN] Endpoint with id 'my-streaming-amf' is closing the streaming connection to FlexClient with id '71E6466F-D91F-201C-F60A-A6CB52F95D9F' because endpoint encountered a socket write error, possibly due to an unresponsive FlexClient.
      ClientAbortException:  java.net.SocketException: Broken pipe
          at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:319)
          at org.apache.catalina.connector.OutputBuffer.flush(OutputBuffer.java:288)
          at org.apache.catalina.connector.Response.flushBuffer(Response.java:542)
          at org.apache.catalina.connector.ResponseFacade.flushBuffer(ResponseFacade.java:279)
          at flex.messaging.endpoints.BaseStreamingHTTPEndpoint.handleFlexClientStreamingOpenRequest(BaseStreamingHTTPEndpoint.java:818)
          at flex.messaging.endpoints.BaseStreamingHTTPEndpoint.serviceStreamingRequest(BaseStreamingHTTPEndpoint.java:1055)
          at flex.messaging.endpoints.BaseStreamingHTTPEndpoint.service(BaseStreamingHTTPEndpoint.java:460)
          at flex.messaging.MessageBrokerServlet.service(MessageBrokerServlet.java:353)
          at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
          at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
          at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
          at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
          at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
          at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
          at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
          at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
          at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:263)
          at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
          at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:584)
          at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
          at java.lang.Thread.run(Thread.java:680)
      Caused by: java.net.SocketException: Broken pipe
          at java.net.SocketOutputStream.socketWrite0(Native Method)
          at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:92)
          at java.net.SocketOutputStream.write(SocketOutputStream.java:136)
          at org.apache.coyote.http11.InternalOutputBuffer.realWriteBytes(InternalOutputBuffer.java:737)
          at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:434)
          at org.apache.coyote.http11.InternalOutputBuffer.flush(InternalOutputBuffer.java:299)
          at org.apache.coyote.http11.Http11Processor.action(Http11Processor.java:963)
          at org.apache.coyote.Response.action(Response.java:183)
          at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:314)
          ... 20 more
      
      [BlazeDS]23:18:13.689 [DEBUG] Streaming thread 'http-8400-1' for endpoint with id 'my-streaming-amf' is releasing connection and returning to the request handler pool.
      [BlazeDS]23:18:13.689 [INFO] Number of streaming clients for FlexSession with id '5BC5E8D604A361BCA673B05AC624CCC1' is 0.
      [BlazeDS]23:18:13.689 [DEBUG] Number of streaming clients for endpoint with id 'my-streaming-amf' is 0.
      

      在此阶段,订阅仍会在ActiveMQ Web管理界面上显示为处于活动状态。

    2. 从控制台使用kill -9杀死BlazeDS(更准确地说,托管它的Tomcat服务器)使ActiveMQ立即意识到“代理JMS客户端”已经消失,并且它在ActiveMQ Web管理员上变为脱机状态接口。这让我得出结论,BlazeDS明确地保持代理JMS客户端活着,因为kill -9没有机会让BlazeDS取消订阅客户端,但它仍然在ActiveMQ中脱机。

    3. 所以,问题再次提出:我可以做些什么来确保BlazeDS在ActiveMQ中使“代理JMS客户端”脱机时其真正的Flex对应物意外终止?这是BlazeDS中的一个错误,还是我错过了一些可以使其工作的隐藏配置设置?

      版本信息:BlazeDS 4.0,ActiveMQ 5.5.0,今天都刚刚下载。我在BlazeDS交​​钥匙中使用Tomcat服务器,但ActiveMQ是单独安装的,因为BlazeDS交​​钥匙仅附带ActiveMQ 4.1.1。顺便说一下,那个版本的ActiveMQ有同样的问题。

1 个答案:

答案 0 :(得分:3)

问题在于BlazeDS无法检测到您的Flex客户端已关闭,您必须实现自己的机制 - 我的建议是使用通过消息传递实现的心跳。如果在一段时间后没有收到客户端的消息,您可以认为Flex客户端已经消失并执行断开连接(或者您可以使用服务器上的会话超时机制,并在会话过期时断开连接)。

您所看到的(流媒体频道关闭时捕获的异常)不足以说100%确定Flex客户端已消失。使用始终保持打开的HTTP连接(用于发送服务器消息)和定期HTTP后呼叫(由客户端发起以发送消息)来实现流式传输。在某些网络中,防火墙可以决定在几秒钟后终止HTTP连接,并且您将收到与您发布的错误相同的错误。但是,这并不意味着Flex客户端被终止 - 在这种情况下,Flex客户端可以使用回退策略并切换到短/长轮询。实际上,如果在这种情况下BlazeDS会自动执行JMS断开连接,那将是一个错误。