2012-10-08 7 views
7

Sto cercando di implementare il polling lungo nel mio Spring-MVC Web App ma congela il mio browser e altre richieste dopo 4-5 continua richieste AJAX. Non ho idea di cosa stia succedendo qui è il mio codice rilevante .Il polling lungo blocca il browser e blocca altre richieste Ajax

Il metodo di controllo: (lato server): -

@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; 
    } 

Lo script-polling lungo (lato client): -

$(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); 

Nessuna finestra di avviso si apre .. :(

+0

penso che si utilizza setTimeout invece di setInterval. Controllare [questo] (http://stackoverflow.com/questions/2696692/setinterval-vs-settimeout) – bhb

+0

penso che non sia il problema per il congelamento è perfetto perché voglio chiamare il metodo solo una volta non ancora e ancora (su successo o errore). –

+0

Vedi qualche problema/errore nel tuo firebug. Se i dati provenienti dal server sono enormi, potrebbero bloccare il browser. – bhb

risposta

5

Sembra che tu abbia un ciclo di tempo vuoto nel codice del tuo browser .. questo è un modo molto istintivo di CPU per attendere un evento.

Se non si verificano eventi, il client ucciderà la richiesta dopo il timeout desiderato di 50 secondi. Ma non sono sicuro che anche il thread del server venga ucciso, o se "si blocca" all'infinito (a meno che non ci sia un evento). La richiesta successiva avvierà un secondo thread del server che si blocca anche nel ciclo while. Forse la quantità di cicli while vuoti è un sovraccarico per il server, quindi smette di accettare altre richieste. Quindi, dopo alcune richieste (ognuna delle quali ha innescato un thread infinito del server) il client attende per sempre una nuova richiesta .. perché non può essere gestita dal server.

ps: in caso di successo si ha commentato aspettare 1 secondo, ma impostare il timeout a 10000 (10 secondi)

+0

Hai ottenuto il tuo punto di vista come posso risolvere questo problema se il codice mi fornisce del codice per eseguire il polling lungo in modo efficiente. Grazie –

+0

Solo per verificare se questo è il motivo aggiungi la seguente riga all'interno del ciclo while: 'Thread.currentThread(). (1000); ' Ciò invierà il thread corrente a sleep per dare agli altri thread la possibilità di eseguire .. Regola il tempo di sospensione al tempo di reazione desiderato .. – lrsjng

+0

Questo non funzionerà man Causa il comportamento thred non è nel nostro controllo, quindi invierà una risposta diversa a ogni client e non possiamo nemmeno garantire che ogni cliente riceva la stessa risposta. Ho provato prima. –

2

Ho incontrato un problema simile, il mio browser è stato bloccato in qualche modo con richieste AJAX. Suggerimento: utilizzando invece waitForMsg() direttamente, prova setTimeout ("waitForMsg()", 10).

+0

provato non funziona il browser mostra ancora il caricamento del simbolo e si blocca. –

2

Cordiali saluti, ecco un progetto che potrebbe aiutare: https://github.com/SeanOC/jquery.comet

In generale, vorrei cercare JavaScript API cometa in grado di supportare i socket web se disponibile sul client/server con fallback elegante per polling lungo. L'API dovrebbe gestire tutti i dettagli cruenti, permettendoti di concentrarti sull'applicazione.

Ecco un link ad un vecchio articolo dojo sul tema: http://dojotoolkit.org/features/1.6/dojo-websocket

Buona fortuna.

+0

Soluzione trovata nel primo collegamento ma non funzionante ... Aggiornamento aggiunto in questione. –

1

Potrebbe essere questo:

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

nella funzione waitForMsg.

Prova

var xhr = (...) 

Può essere che si dichiara XHR nell'oggetto globale, rendendo così impossibile per rispondere a due richieste differenti.

2

Si può provare a riscrivere il comportamento utilizzando jQuery differita:

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 e successHandler sarà il vostro successo: e di errore: callback, che ho omesso per chiarezza, con la loro parte setTimeout rimosso (dal momento che è ora fa parte dei callback deferred.done() e .fail()).

Fammi sapere se funziona.

2

Sono uno sviluppatore PHP ma ho incontrato il problema e potrebbe essere lo stesso comportamento. Quindi ti do i miei 2 centesimi e spero che ti possa aiutare.

La linea che non mi fanno sospetto un problema è:

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

In PHP, le sessioni sono memorizzate in file, e se siamo a lungo polling su uno script php mentre la sessione è aperta, si incontrano un problema race condition.

Il principio è molto semplice:

  1. Quando una richiesta si apre la sessione, file è bloccato fino a quando la sessione è chiuso.
  2. Se altre richieste arrivano al server, verranno bloccate fino a quando la sessione non viene rilasciata dalla richiesta precedente.

In un caso di polling lungo, se la sessione è aperta e non chiusa solo dopo aver ottenuto le informazioni (almeno, poco prima in attesa di eventi), tutte le richieste sono solo bloccati, non si può andare in qualsiasi altra parte il sito Web se stai utilizzando sessioni su altre pagine. Anche se apri una nuova scheda, perché per un browser c'è solo una sessione, sei bloccato.

+0

Lo sto facendo perché voglio riflettere la stessa notifica di evento per ogni browser utente, quindi il miglior ambito è il Contesto. Proverò cosa hai proposto.Ma php hai session_write_close non penso che java abbia una cosa del genere –

9

Sembra come avete sperimentato bloccare il file della sessione

Per PHP

Usa session_write_close() quando non è necessario valore di sessione

+0

non proprio quello che l'op ha chiesto, ma è stato upvoted perché era esattamente quello che stavo cercando – emerino