Long polling freezes browser and block other ajax request

回眸只為那壹抹淺笑 提交于 2019-12-21 12:19:37

问题


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..:(


回答1:


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)




回答2:


Seems like you experienced the session file lock

For PHP

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




回答3:


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




回答4:


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.




回答5:


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.




回答6:


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.




回答7:


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.



来源:https://stackoverflow.com/questions/12776531/long-polling-freezes-browser-and-block-other-ajax-request

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!