Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Remote Application Platform (RAP) » Cleanup (Again)
Cleanup (Again) [message #633816] Tue, 19 October 2010 14:00 Go to next message
Markus  rüger is currently offline Markus rügerFriend
Messages: 369
Registered: July 2009
Senior Member
Hello to all,

I know cleanup of a session is a discussed in many threads, but I could not
find an answer to my question.
I have one Job that monitors all session. If this jobs recognizes an unload
(due to a the known hack to DisplayLCA) or a "beforeDestroy", then my job
cleans up the belonging session.
This works in most cases, but not if the browser or os crashes. This way
either unload or beforeDestroy is called, which is quiete reasonable to me.
The methods display.addListener(SWT.Close,...) and display.disposeExec(...)
do not work either. Just if the timeout is reached I get beforeDestroy and
the the session cleans up.
The Problem is, that we do not allow multiple logins with the same username.
This means, that if I login as user "User1" and my browser crashes or some
uncaught "Browser close" actions
occur than the user "User1" can not login until the timeout was reached.
We can lower the timeout, but 30min is actually a good setting as we
discussed in a meeting.

My question now is, if there is any call that I can make in my job to check
if the session still exists in a browser?
I tried Display.isDisposed and a lot of calls to workbench and views. All
calls I tested give me "good results" as if
the workbench stillt exists.
Is there anything I did not find, oder is there just nothing we can do about
this?

Regards,
Markus
Re: Cleanup (Again) [message #633839 is a reply to message #633816] Tue, 19 October 2010 14:54 Go to previous messageGo to next message
Cole Markham is currently offline Cole MarkhamFriend
Messages: 150
Registered: July 2009
Location: College Station, TX
Senior Member

Markus,

One idea would be to run a Display.asyncExec on each of the displays. Wait some appropriate period (30 seconds, 5 minutes?) depending on your application usage and whether you have the application polling and/or UICallback active. Once the timeout has expired you see which displays actually ran the runnable, and those are the active ones.

That brings up an interesting point: there should probably be an easy way to have the app poll at a regular interval. We have a somewhat hacked solution with a custom widget that implements a timer on the client side. It would be nice if RAP provided this functionality out of the box, or maybe it does and we just missed it.

Cole
Re: Cleanup (Again) [message #634001 is a reply to message #633839] Wed, 20 October 2010 08:39 Go to previous messageGo to next message
Markus  rüger is currently offline Markus rügerFriend
Messages: 369
Registered: July 2009
Senior Member
Hi Cole,

maybe my explanation was not clear. We have no problem after a timeout has
reached, we have a problem between browser termination (i.e. kill in
taskmanager) and the timeout as our User1 can not log into until timeout has
been reached. If timeout occurs, then everthing works.

Regards,
Markus

"Cole Markham" <markhamc@tamu.edu> schrieb im Newsbeitrag
news:i9kb8g$gk3$1@news.eclipse.org...
> Markus,
>
> One idea would be to run a Display.asyncExec on each of the displays. Wait
> some appropriate period (30 seconds, 5 minutes?) depending on your
> application usage and whether you have the application polling and/or
> UICallback active. Once the timeout has expired you see which displays
> actually ran the runnable, and those are the active ones.
> That brings up an interesting point: there should probably be an easy way
> to have the app poll at a regular interval. We have a somewhat hacked
> solution with a custom widget that implements a timer on the client side.
> It would be nice if RAP provided this functionality out of the box, or
> maybe it does and we just missed it.
>
> Cole
Re: Cleanup (Again) [message #634388 is a reply to message #634001] Thu, 21 October 2010 14:08 Go to previous messageGo to next message
Cole Markham is currently offline Cole MarkhamFriend
Messages: 150
Registered: July 2009
Location: College Station, TX
Senior Member

Markus,

I understand your problem as we have a similar issue detecting defunct sessions. In our case it is more critical since a shared background thread is calling Display.syncExec (not a good idea, btw) which blocks the thread for the entire system. Changing the session timeout is not really an option for us because it would need to be on the order of seconds. Thus I came up with a watchdog which monitors the background thread and detects when it is blocked. Then it calls this method to clean up defunct displays.

protected void cleanupDefunctDisplays()
   {
      List<IWorkbenchProvider> workbenchProviders = Activator.getDefault().getServices(IWorkbenchProvider.class);
      final List<IWorkbench> pendingResponse = new CopyOnWriteArrayList<IWorkbench>(); 
      CountDownLatch countDownLatch = new CountDownLatch(workbenchProviders.size());
      
      for (IWorkbenchProvider wbProvider: workbenchProviders) {
         final IWorkbench wb = wbProvider.getWorkbench();
         Display display = wb.getDisplay();
         if (display == null || display.isDisposed()) {
            // display is already dead, call countDown to be sure we don't wait uneccesarily and move along
            countDownLatch.countDown();
            continue;
         }
         // mark as pending response
         pendingResponse.add(wb);
         display.asyncExec(new Runnable()
         {
            public void run()
            {
               // it only runs this when the client is still alive, so remove from the list
               pendingResponse.remove(wb);
            }
         });
      }
      // wait at most 5 seconds because there is a polling refresh at that interval
      try {
         countDownLatch.await(5, TimeUnit.SECONDS);
      } catch (InterruptedException e) {
         // Thread was interrupted, just bail
         e.printStackTrace();
         return;
      }
      for (final IWorkbench wb: pendingResponse) {
         // this display is not responding, so kill it
         // TODO is this the best way to close? call display.dispose()? use IWorkbenchConfigurer.emergencyClose()?
         try {
            Display display = wb.getDisplay();
            if (display != null && !display.isDisposed() && !wb.isClosing()) {
               IDisplayAdapter displayAdapter = (IDisplayAdapter)display.getAdapter(IDisplayAdapter.class);
               // HACK Synchronizer doesn't release locks on dispose, see bug 328347
               while(displayAdapter.getAsyncRunnablesCount() > 0) {
                  try {
                     Method method = IDisplayAdapter.class.getMethod("runAsyncRunnables");
                     method.setAccessible(true);
                     method.invoke(displayAdapter);
                  } catch (Exception e) {
                     e.printStackTrace();
                  }
               }
               // kill the session which should cleanup everything else
               displayAdapter.getSession().getHttpSession().invalidate();
            }
         } catch (Exception e) {
            e.printStackTrace();
         }
      }
      
   }


A few notes:
- IWorkbenchProvider is something we use which allows us to enumerate all of the active workbench sessions and therefore get their display. You would need to provide something similar to get the displays.

- Display.dispose and/or IWorkbench.close can only be called from the UI thread, so the best option for cleaning up is to invalidate the session. This is basically what happens on a session timeout so the behavior should be similar.

- The ugly hack using reflection is only for the problem we are having with syncExec, you should be able to remove it for your purposes.

- The biggest caveat is the timeout on the countdown latch. This must be set long enough that the client has a chance to respond and run the asyncExec, but obviously you want to limit how long you wait. Since you can't wait for user interaction, there are two ways to ensure the client responds within this timeout period:
1. Use a session-long UICallback. We do this, but it is not recommended by the RAP team. See other newsgroup posts on the subject.
2. Force the client to poll at a regular interval. We do this as well as a backup. As I mentioned in my previous post, we use custom widget but it would be nice if there was a framework solution. Just a note, Display.timerExec will not work for this since it only runs on the server and has to wait on client request just like asyncExec.

We already needed the client to frequently poll in order to push information from the backend to the client without user interaction (e.g., update a table when another user changes it), so it wasn't an extra burden just to solve this problem. You may or may not have similar needs. As far as using this method for your problem: I would think that when the user tries to log in you would take his credentials, determine if he is already logged in, then display a progress dialog while this method runs. You could set the countdown latch timeout to something like 30 seconds if you wanted to have your client poll less frequently.

Hope this helps,

Cole
Re: Cleanup (Again) [message #634615 is a reply to message #633816] Fri, 22 October 2010 12:42 Go to previous message
Ralf Sternberg is currently offline Ralf SternbergFriend
Messages: 1313
Registered: July 2009
Senior Member

Hi Mark,

> My question now is, if there is any call that I can make in my job to
> check if the session still exists in a browser? I tried
> Display.isDisposed and a lot of calls to workbench and views. All calls
> I tested give me "good results" as if the workbench stillt exists.
> Is there anything I did not find, oder is there just nothing we can do
> about this?

How could you tell from the server whether a browser is still open but
not sending requests or if it has crashed meanwhile? I think you just
can't unless you have some way to talk to the client. That would be the
UICallBack. With a running UICallBack, it could be possible to detect a
dead client (but currently it's not).

When we answer a UICallBack request (triggered by an asyncExec), we would
not get a request back since there is no client anymore. We could take
that as a sign that the client must be dead and timeout the session. That
could be an extension to bug 284273. Maybe there will once be better ways
with Web Sockets.

One thought regarding the other option, letting the client poll the
server on a regular interval: I once had the idea to combine the
UICallBack with such a (configurable) interval, so that no UICallBack
request would not wait forever if no UI updates are available but will be
answered after this period of time at the latest. If you think this would
help, feel free to file a bug.

Another thought: wouldn't it be an option to let the user decide in this
rare case? Present a dialog like "You seem to have opened this site in
another browser window already. If you continue here, your changes over
there will be lost"...

Best regards, Ralf

--
Ralf Sternberg

Need professional support for RAP and RCP?
http://www.eclipsesource.com/support/

Twitter: http://twitter.com/eclipsesource
Blog: http://www.eclipsesource.com/blogs/
Previous Topic:How to call Web Service form Rich Ajax Platform (RAP)?
Next Topic:Deploy RAP Application to WebSphere OSGI Container
Goto Forum:
  


Current Time: Fri Apr 26 17:08:37 GMT 2024

Powered by FUDForum. Page generated in 0.03068 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top