Saturday, May 1, 2010

A Smarter Flex ChannelSet

The ChannelSet class in the Adobe Flex Framework is pretty brilliant. For example, lets say we were building an online auction application using LCDS(LiveCycle Data Services) where users can submit bids on items. We would want this application to be Real-Time. Our first choice for how the client connects to the back-end should be the RTMP protocol using the RTMPChannel class. This type of connection beats out any other connections out there. It beats streaming/comet and polling type connections by a long shot. But lets say some of our users are behind strict firewalls that will not allow them to connect using the RTMP protocol. Does this mean these users will not be able to use our application? Nope, this is why the ChannelSet class is so brilliant. We can provide the client with backup/failover channels to connect on. Take a look at the example below.

   
   
   

Notice above I created a ChannelSet with three channels defined. The client will attempt to connect using the RTMP channel first. If the client fails on RTMP, it will attempt on streaming. If the client fails on streaming, it will attempt on the long polling channel. As a developer this is nice as I don't have to code any of this fail over logic. This functionality is baked right into the ChannelSet class. There is only one problem with the ChannelSet class. The problem arises when a client connects, disconnects and then connects again. The client might get disconnected due to loosing their wireless internet. When the client gets disconnected, the ChannelSet class "connection logic" will kick in gear and attempt to connect by looping over the channels until one channel successfully connects. This might be fine for some situations, but let me explain a particular situation where you don't want this to happen.

For example, a user initially connects using RTMP. The user is using the application for awhile, but all of a sudden they lose their internet connection. The ChannelSet class is made aware of the disconnect and its "connection logic" kicks into gear and loops over each channel attempting to connect until one is successful. The users internet connection than comes back online. The user for some reason is now connected using long polling. What! Why the heck is the user connected using the long polling channel when the user initially connected using the RTMP channel. The answer is because the ChannelSet class "connection logic" is just a simple loop over the channels and when the users internet came back, the loop was currently attempting to connect on the long polling channel and it did. That is why the user is now connected over the long polling channel.

So, basically to sum up this problem. The user initially connected over RTMP, gets disconnected, re-connects and connects over long polling that is on the bottom of our channel list. How do we fix this little problem? Simple, we create a smarter ChannelSet class. Take a look at the smarter ChannelSet class that I named "CustomChannelSet" below.
package net.flashdan.util {
 import mx.messaging.Channel;
 import mx.messaging.ChannelSet;
 import mx.messaging.events.ChannelEvent;
 
 public class CustomChannelSet extends ChannelSet {
  
  public function CustomChannelSet(channelIds:Array=null, clusteredWithURLLoadBalancing:Boolean=false) {
   super(channelIds, clusteredWithURLLoadBalancing);
   addEventListener(ChannelEvent.CONNECT, onChannelConnect);
  }
  
  private function onChannelConnect(event:ChannelEvent):void {
   //loop through the channels for this channelset and remove all but the connected one
   for (var i:int=channels.length-1;i>=0;i--) {
    var channel:Channel = channels[i] as Channel;
    if(channel.id != currentChannel.id){
     removeChannel(channel);
    }
   }
  }
 }
}
We would then use our CustomChannelSet like so.

   
   
   

The solution is pretty simple. When the user initially connects over a particular channel, remove all other channels except the currently connected channel. This way when the user initially connects over RTMP, gets disconnected, re-connects, the ChannelSet "connection logic" only attempts to connect over the RTMP channel and no others. Problem solved! I am providing a small sample flex application with the SmarterChannelSet class being used. It's a Flex 4 project. Unzip the file and import the .fxp project in Flash Builder 4.
Download Source

4 comments:

  1. This an elegant solution. However there's one caveat: if the user reconnects on a different network where is maybe behind a firewall the RTMP connection might not work over there.

    Mihai Corlan

    ReplyDelete
  2. Mihai, you bring up a good point. In my case that scenario would be very unlikely to happen. Most of my users are behind hospital networks and when they reconnect, they connect to the same network. Anyway, you still bring up a good point.

    ReplyDelete
  3. As Mihai said, quite an elegant and simple solution, but the problem arises when the user reconnects on a different network.


    To solve this, I would add a public property to your CustomChannelSet, which would be the "primary" channel, so when the user disconnects, and then reconnect to a different newtwork, it will first try on that "primary" channel and if no success, then continue the looping.



    Marc Enriquez

    ReplyDelete
  4. This is a good solution..Dan can you please help me out with an issue in Lcds 2.6.1,,

    Hope you can help me out with this issue. we were using LCDS 2.5 with IE 6. Then we upgraded to LCDS 2.6.1. We have been using SSL with the same version of IE for almost 3 months and we never had this issue. there was no change in the related code and the only change we did was that we upgraded LCDS version to 2.6.1 with the latest version to 2.6.1 with the latest release. just curious if you are aware of anything different in LCDS 2.6.1 that would cause IE 6 to behave like that? Firefox works fine..i also noticed that there is channel fail-over in Charles(Web Debugging tool) session. Basically it took about 1min and 20 sec to fail-over from amfsecure channel to amfvsecure channel. Why there's a channel fail-over happen?? in the worst cases, the fail-over never happens and it keeps clocking until user close the browser. Is there any configuration for time out and retry before fail-over occurs?? if you wonder why we configure 2 channels , but both use the same end point. i also think about whether servlet session could relate to this issue since AMF is an http base channel. Since the issue only happens to the new users, could the servlet session was maxed out and/or being cached until server restarts.

    Thanks
    Lucky

    ReplyDelete