LCDS & Flex - Preventing DuplicateHTTPSession errors after logout

2.8k views Asked by At

I have a flex/LCDS stack, where I'm finding that after logout, I often (but not always) start receiving Duplicate HTTP Session errors on the client.

Here's the important facts of the stack:

  • The flex client has a login/logout functionality within the app. The page does not refresh after the logout. (Therefore, the Flex app, and the underlying mx.messaging.FlexClient remains initialised)
  • A user may have multiple tabs open.
  • per-client-authentication is set to false - we're trying to achieve SSO (integrating with CAS) so the user principle is bound to the JSession.
  • The problem is most evident when using long-polling for messaging, and when there are two (or more) tabs open.
  • The problem is very difficult to reproduce when using RTMP or Streaming channels.
  • A user is bound to a JSession - ie., if they log in on Tab1, they become logged in on Tab2.
  • When a user logs out from either tab, the Jsession is invalidated.

Here's my current theory as to what's causing the issue:

  • Tab1 (T1) Starts client -> Issued ClientId1 (C1) -> JSession1 (J1) created
  • Tab2 (T2) Starts Client -> Issued ClientId2 (C2) -> Joins J1
  • T1 logs in -> J1 Unaffected
  • T2 logs in -> J1 Unaffected
  • T1 & T2 Both subscribe, start polling over amflongpolling
  • T1 sends logout -> J1 Invalidated -> J2 created
  • T2 sends poll (against J1)
  • T1 logout completes, returns with J2, updates cookie

The last two calls create a conflict, where the LCDS sees the FlexClient appears to be related to 2 JSessions.

As a result, an error along the lines of the following is recieved:

Server.Processing.DuplicateSessionDetected Detected duplicate HTTP-based FlexSessions, generally due to the remote host disabling session cookies. Session cookies must be enabled to manage the client connection correctly.

Note: I've been able to recreate the problem in a stand-alone project. I believe it's not an issue with our application specific code, instead caused by the Stateful / session nature and conflicts between multiple tabs sharing the same session.

In summary, I believe the issue is caused where the session is invalidated on the server as a result of calls from one tab, but before the response is sent to the browser to inform it of the new JSession, calls are issued under the old Jsession.

What are some appropriate strategies to defend against this duplicate session issue?


Update

To clarify, while the scenario is similar to those discussed here, there are subtle differences which make the solutions in that article inappropriate.

Specifically, the article discusses preventing duplicate sessions by controlling the initial creation of JSessions across both browsers, using a JSP, or an orchestrated RemoteObject call.

Flex actually assists in this process by preventing outbound RemoteObject calls until the local FlexClient DSid variable is defined, showing that the initial session has been established.

My scenario differs, because the JSession (& associated LCDS FlexSession / Client-Side FlexClient objects) have already been established once, (using the techniques discussed in that article) and subsequently invalidated via logout - which calls session.invalidate() - destroying the JSession.

The issue arises when Tab2 sends a call with a stale JSession, a duplicate HTTP Session error. The situation then gets compounded, as when LCDS throw the DuplicateHTTPSession error, it also invalidates all known Jsessions attached with the client, meaning that the Tab1 - which had been ok - now has a stale JSession. The next time that Tab1 sends a call, IT causes a DuplicateHTTPSession error, and the cycle repeats.

Unfortunately, the Flex framework hooks for delaying calls while sesssions are established have no easy way (that I've found) of being re-enabled once set. (I've tried the following, to no avail:)

 // Reset DSid to get a new FlexSession established on LCDS
   use namespace mx_internal

   public function resetFlexSession()
   {
        FlexClient.getInstance().id = null;  
        // Note - using FlexClient.NULL_ID also doesn't work.
   }
3

There are 3 answers

1
gMale On

This article titled, Avoiding duplicate session detected errors in LCDS, gives an in-depth explanation of what's happening in your situation. Here is a relevant quote:

...[LCDS] believes that the FlexClient it received the request from was already associated with a different session on the server.

For the client application to make sure that FlexClients in the application don’t get into this bad state, the client application must make sure that a session is already established on the server before multiple FlexClients connect to the server at the same time.

There are several approaches recommended to fixing this, including:

  • calling a jsp page to load the application
    "The jsp page could both create a session for the client application and return an html wrapper to the client which would load the swf."
  • calling a Remoting destination
    "which would automatically create a session for the client application on the server"
0
PRB On

I feel for you - I've fought this for a long time and never found a solution, but found a fix that worked for me so hopefully it will at least keep this issue under control until you can find the culprit. (And if you do, please post it here).

Now, I've got a slightly different environment than you (I'm using CF on the backend) so keep that in mind.

I also tried the whole "FlexClient.getInstance().id = null;" thing too and it didn't work by itself, but it was how and where I implemented it that made it work.

So, this is what I did that made the problem go away.

On my main form, before ANY RemoteServer calls are made, I setup a creationComplete handler and placed this code you already know and love:

// Not sure if this is needed anymore, but I'm leaving it in
FlexClient.getInstance().id = null;

Next, in my very first call to the server, I gracefully handle the failure, and clear that stinking ID out again:

    public function login(event:Event): void {

        Swiz.executeServiceCall(roUsers.login(),
            function (event:ResultEvent): void {
                // Handle a successful login here...
            }
            , function (faultevent:FaultEvent): void {
                // This code fixes this issue with IE tabs dying and leaving Flex with a Duplicate Session problem.
                if (faultevent.fault.faultString.indexOf("duplicate")) {
                  FlexClient.getInstance().id = null;
                  Swiz.dispatchEvent(event);
                }
        });

    }

And it worked.

Basically, try the call, and if it fails for the duplicate session thing, then clear out that ID and reissue the call.

The key point being that I don't think clearing out the ID works until you've made at least one call to the server. Once you do, it worked like a CHARM for me, and in all of my apps.

Note that I'm using the SWIZ framework above so just translate it to your own world.

By the way, I've never seen this error in any other browser but IE, and I believe it may have something to do with the infamous Dead Tab Issue that IE suffers from.

If the above doesn't work, I also know of a few changes to some config files on the server that might help.

Good luck my friend!

0
Gaius Coffey On

An additional, unrelated, cause to be aware of;

Some browsers (Internet Explorer, for example) apply domain naming rules to cookies and this means that a code domain like "my_clientX.server.com", although it may return valid BlazeDS responses, will continually trigger duplicate session notifications as access to the cookie will be blocked.

Changing the name to a valid name (without underscore) will resolve the issue.