2012-10-08 79 views
7

Estoy tratando de implementar una larga encuesta en mi Spring-MVC Web App pero congela mi navegador y otras solicitudes después de que 4-5 continúen las solicitudes de AJAX. No tengo idea de qué sucede aquí es mi código relevante .Encuesta larga congela el navegador y bloquea otra solicitud de ajax

El método controlador: (el lado del servidor): -

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

El script-sondeo de largo (lado del cliente): -

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

Ningún cuadro de alerta aparece .. :(

+0

creo que se está utilizando en lugar de setTimeout setInterval. Compruebe [esto] (http://stackoverflow.com/questions/2696692/setinterval-vs-settimeout) – bhb

+0

Creo que no es el problema de la congelación, es perfecto porque quiero llamar al método una sola vez, no una y otra vez (en éxito o error). –

+0

¿Ve algún problema/error en su firebug? Si los datos que provienen del servidor son enormes, podrían congelar el navegador. – bhb

Respuesta

5

Parece que tiene un bucle de tiempo vacío en el código de su navegador ... esta es una forma muy intensiva de esperar un evento.

Si no ocurre ningún evento, el cliente cancelará la solicitud después del tiempo de espera deseado de 50 segundos. Pero no estoy seguro si el hilo del servidor también se elimina, o si se "apaga" para siempre (a menos que haya un evento). La siguiente solicitud iniciará una segunda cadena de servidor que también se cuelga en el ciclo while. Tal vez la cantidad de ciclos while vacíos es excesiva para el servidor, por lo que deja de aceptar más solicitudes. Entonces, después de algunas solicitudes (que cada una desencadenó un hilo de servidor interminable) el cliente espera por siempre una nueva solicitud ... porque no puede ser manejada por el servidor.

ps: el éxito que ha comentado que esperar de 1 segundo, pero establece el tiempo de espera a 10000 (10 segundos)

+0

Entender cómo puedo resolver este problema si me proporcionas código para hacer un sondeo largo de manera eficiente.gracias –

+0

Solo para verificar si este es el motivo, agrega la siguiente línea dentro del ciclo while: 'Thread.currentThread(). Sleep (1000); ' Esto enviará el hilo actual a dormir para que otros hilos tengan la oportunidad de ejecutarse .. Ajuste el tiempo de sueño al tiempo de reacción deseado. – lrsjng

+0

Esto no funcionará porque el comportamiento no está bajo nuestro control, por lo que enviará una respuesta diferente a cada cliente y ni siquiera podemos asegurarnos de que cada cliente reciba la misma respuesta. Lo he intentado antes. –

2

Me he encontrado con un problema similar, mi navegador se vio afectado de alguna manera con las solicitudes AJAX. Sugerencia: en su lugar, usando waitForMsg() directamente, intente setTimeout ("waitForMsg()", 10).

+0

intenté no funciona el navegador todavía muestra el símbolo de carga y se congela. –

2

FYI, aquí es un proyecto que podría ayudarle a: https://github.com/SeanOC/jquery.comet

En general, me gustaría buscar las API de JavaScript de cometas que pueden apoyar los zócalos web si está disponible en cliente/servidor con repliegue elegante de sondeo largo. La API debe manejar todos los detalles sangrientos, lo que le permite centrarse en la aplicación.

Aquí hay un enlace a un viejo artículo dojo sobre el tema: http://dojotoolkit.org/features/1.6/dojo-websocket

Buena suerte.

+0

Solución probada en su primer enlace pero no funciona ... Se agregó la actualización en cuestión. –

1

Puede ser esta:

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

en su función waitForMsg.

Trate

var xhr = (...) 

Puede ser que está declarando xhr en el objeto global, por lo que es imposible responder a dos solicitudes diferentes.

2

Usted puede tratar de reescribir el comportamiento usando jQuery diferida:

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 y successHandler será su éxito: y de error: devoluciones de llamada, que he omitido para mayor claridad, con su parte setTimeout eliminado (ya que es ahora forma parte de las devoluciones de llamada deferred.done() y .fail()).

Avísame si funciona.

2

Soy un desarrollador PHP pero conocí su problema y podría ser el mismo comportamiento. Así que te doy mis 2 centavos y espero que te ayude.

La línea que me hace sospechar un problema es:

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

En PHP, las sesiones se almacenan en archivos, y si somos largo de votación en un script php mientras que la sesión está abierta, nos encontramos un problema race condition.

El principio es muy simple:

  1. Cuando una solicitud abre la sesión, archivo está bloqueado hasta que la sesión se cierra .
  2. Si llegan otras solicitudes al servidor, se bloquearán hasta que se libere la sesión de la solicitud anterior.

En caso de una larga encuesta, si la sesión se abre y no se cierra justo después de obtener información (al menos, justo antes de esperar eventos), todas las solicitudes están bloqueadas, no se puede ir a ninguna otra parte el sitio web si usa sesiones en otras páginas. Incluso si abre una pestaña nueva, porque para un navegador solo hay una sesión, está bloqueado.

+0

Lo estoy haciendo porque quiero reflejar la misma notificación de eventos en todos los navegadores de los usuarios, así que el mejor alcance es Contexto. Creo que sí. Voy a probar lo que has propuesto. Pero php tiene session_write_close, no creo que Java lo tenga. –

9

parece que ha experimentado bloquear el archivo de sesión

Para PHP

Uso session_write_close() cuando no se necesita valor de sesión

+0

no es lo que el operador pidió, pero votó a favor porque era exactamente lo que estaba buscando. – emerino

Cuestiones relacionadas