Long polling freezes browser and block other ajax request
Asked Answered
D

7

8

I am trying to implement long polling in my Spring-MVC Web App but it freezes my browser and other request after 4-5 continues AJAX requests.I have no clue whats goin on here is my relevant code.

The controller method:(Server Side):-

@Asynchronous
    @RequestMapping("/notify")
    public @ResponseBody
    Events notifyEvent(HttpServletRequest request) {
        Events events = null;
        try {
            events = (Events) request.getSession(false).getServletContext().getAttribute("events");
            System.out.println("Request Came from" + ((com.hcdc.coedp.safe.domain.User) request.getSession(false).getAttribute(Constants.KEY_LOGGED_IN_USER)).getLoginId());
            if (!events.getTypeOfEvents().isEmpty()) {
                System.out.println("Removing older entries");
                events.getTypeOfEvents().clear();
            }
            while (!events.isHappend()) {
                //Waiting for event to happen.
            }
            events = Events.getInstance();
            events.setHappend(false);
            request.getSession(false).getServletContext().setAttribute("events", events);

        }catch (Exception e) {
            e.printStackTrace();
        }
        return events;
    }

The long-polling script(Client Side):-

$(document).ready(function() {
                    $.ajaxSetup({
                        async:true//set a global ajax requests as asynchronus
                    });
                     alert('Handler for .onload() called.');
                    waitForMsg();

                });
                function waitForMsg(){

                    xhr=  $.ajax({
                        type: "POST",
                        url: '<%=request.getContextPath()%>/notification/notify',

                        async: true, /* If set to non-async, browser shows page as "Loading.."*/
                        cache: false,
                        timeout:50000, /* Timeout in ms */
                        global:false,
                        success: function(data){ /* called when request to notifier completes */
                          /* Doing smthing with response **/
                            setTimeout(
                            waitForMsg, /* Request next message */
                            1000 /* ..after 1 seconds */
                        );
                        },
                        error: function(XMLHttpRequest, textStatus, errorThrown){
                            addmsg("error", textStatus + " (" + errorThrown + ")");
                            setTimeout(
                            waitForMsg, /* Try again after.. */
                            15000); /* milliseconds (15seconds) */
                        }
                    });
                };

UPDATE:

function updateFeed(event, data) {
                var f=eval(data);
                alert(f.typeOfEvents.length);
            }

            function catchAll(event, data, type) {
                console.log(data);
                alert("error");
                console.log(type);
            }

            $.comet.connect('<%=request.getContextPath()%>/notification/notify');
            $(document).bind('feed.comet', updateFeed);
            $(document).bind('.comet', catchAll);

Neither alert box pops up..:(

Dichlorodiphenyltrichloroethane answered 8/10, 2012 at 6:41 Comment(5)
i think you are using setTimeout instead of setInterval. Check thisKnobloch
i think its not the problem for freezing it is perfect because i want to call method only once not again and again(on sucess or error).Dichlorodiphenyltrichloroethane
Do you see any problem/error in your firebug. If the data coming from the server is huge, it could freeze the browser.Knobloch
No error in firebug.And data also String content only.Dichlorodiphenyltrichloroethane
How many simultaneous connection are there? Some browsers limits to 2/webpage.Pharmaceutical
C
5

It seems you have an empty while loop in your browser code.. this is a very CPU instensive way to wait for an event.

If no events happen the client will kill the request after your desired timeout of 50 seconds. But I'm not sure if the server thread is killed too, or if it "whiles" on forever (unless there is an event). The next request will start a second server thread that hangs in the while loop too then. Maybe the amount of empty while loops is an overkill for the server, so that it stops accepting any more requests. So after some requests (that each triggered an endless server thread) the client waits forever on a new request.. because it can't be handled by the server.

ps: on success you commented to wait 1 second, but set the timeout to 10000 (10 seconds)

Corruptible answered 13/10, 2012 at 12:42 Comment(6)
Got your point how can i resolve this issue if you code provide me some code to do long polling efficiently.thanksDichlorodiphenyltrichloroethane
Just to check if this is the reason add the following line inside the while loop: Thread.currentThread().sleep(1000); This will send the current thread to sleep to give other threads the chance to run.. Adjust the sleep time to the desired reaction time..Corruptible
This won't work man Cause thred behavior is not in our control so it will send different response to every client and we can't even ensure that every client recieves the same response.I have tried thid before.Dichlorodiphenyltrichloroethane
your question and the problem at the moment is, why your browser freezes.. and question is if a server overload is the reason for that. does this change still produce browser freeze?Corruptible
@DanglingPiyush does it still freeze?Corruptible
@Irsjng yeah..:(..I think i need i different approach to achieve this.Dichlorodiphenyltrichloroethane
L
10

Seems like you experienced the session file lock

For PHP

Use session_write_close() when you don't need session value

Limerick answered 14/12, 2013 at 6:58 Comment(1)
not really what the op asked, but upvoted because it was exactly what I was looking forDowlen
C
5

It seems you have an empty while loop in your browser code.. this is a very CPU instensive way to wait for an event.

If no events happen the client will kill the request after your desired timeout of 50 seconds. But I'm not sure if the server thread is killed too, or if it "whiles" on forever (unless there is an event). The next request will start a second server thread that hangs in the while loop too then. Maybe the amount of empty while loops is an overkill for the server, so that it stops accepting any more requests. So after some requests (that each triggered an endless server thread) the client waits forever on a new request.. because it can't be handled by the server.

ps: on success you commented to wait 1 second, but set the timeout to 10000 (10 seconds)

Corruptible answered 13/10, 2012 at 12:42 Comment(6)
Got your point how can i resolve this issue if you code provide me some code to do long polling efficiently.thanksDichlorodiphenyltrichloroethane
Just to check if this is the reason add the following line inside the while loop: Thread.currentThread().sleep(1000); This will send the current thread to sleep to give other threads the chance to run.. Adjust the sleep time to the desired reaction time..Corruptible
This won't work man Cause thred behavior is not in our control so it will send different response to every client and we can't even ensure that every client recieves the same response.I have tried thid before.Dichlorodiphenyltrichloroethane
your question and the problem at the moment is, why your browser freezes.. and question is if a server overload is the reason for that. does this change still produce browser freeze?Corruptible
@DanglingPiyush does it still freeze?Corruptible
@Irsjng yeah..:(..I think i need i different approach to achieve this.Dichlorodiphenyltrichloroethane
P
2

I've met similar problem, my browser was stucked somehow with AJAX requests. Hint: instead using waitForMsg() directly, try setTimeout("waitForMsg()",10).

Pharmaceutical answered 12/10, 2012 at 9:26 Comment(1)
tried not working browser still show loading symbol and freezes.Dichlorodiphenyltrichloroethane
C
2

FYI, here is a project that might help you: https://github.com/SeanOC/jquery.comet

In general, I would search for JavaScript comet APIs that can support web sockets if available on client / server with graceful fallback to long polling. The API should handle all the gory details, allowing you to focus on the application.

Here's a link to an old dojo article on the topic: http://dojotoolkit.org/features/1.6/dojo-websocket

Good luck.

Chiller answered 12/10, 2012 at 19:14 Comment(1)
Tried solution in your first link but not working...Update added in question.Dichlorodiphenyltrichloroethane
C
2

You can try to rewrite the behaviour using jQuery deferred:

function setShortTimeout() {
    setTimeout(waitForMsg, 1000);
}

function setLongTimeout() {
    setTimeout(waitForMsg, 15000);
}

$(document).ready(function() {
                $.ajaxSetup({
                    async:true//set a global ajax requests as asynchronus
                });
                alert('Handler for .onload() called.');
                $.when(waitForMsg())
                    .done(successHandler, setShortTimeout)
                    .fail(errorHandler, setLongTimeout);

            });

            function waitForMsg(){
                return $.ajax({
                    type: "POST",
                    url: '<%=request.getContextPath()%>/notification/notify',
                    async: true, /* If set to non-async, browser shows page as "Loading.."*/
                    cache: false,
                    timeout:50000, /* Timeout in ms */
                    global:false
                });
            };

errorHandler and successHandler will be your success: and error: callbacks, which I omitted for clarity, with their setTimeout part removed (since it is now part of the deferred.done() and .fail() callbacks).

Let me know if it works.

Cornelius answered 18/10, 2012 at 11:2 Comment(0)
E
2

I am a PHP developer but I met your problem and it could be the same behaviour. So I give you my 2 cents and hope it'll help you.

The line that does make me suspect a problem is :

events = (Events) request.getSession(false).getServletContext().getAttribute("events");

In PHP, sessions are stored in files, and if we are long-polling on a php script while the session is open, we meet a race condition problem.

The principle is quite simple :

  1. When a request opens the session, file is locked until the session is closed.
  2. If other requests comes to the server, they will be locked until the session is released from the previous request.

In a case of long polling, if the session is opened and not closed just after getting information (at least, just before waiting for events), all requests are just locked, you can't go anywhere else in the website if you're using sessions on other pages. Even if you open a new tab, because for one browser there is only one session, you're locked.

Ewing answered 18/10, 2012 at 22:4 Comment(1)
I am doing so because I want to reflect same event notification to every user browser so the best scope is I think Context. But i'll give it a try what you have proposed.But php have session_write_close i don't think java have such thing.Dichlorodiphenyltrichloroethane
T
1

It may be this:

        xhr=  $.ajax({ (...)

in your waitForMsg function.

Try

    var xhr = (...)

It may be that you are declaring xhr in the global object, thus making it impossible to respond to two different requests.

Tovatovar answered 18/10, 2012 at 9:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.