2015-08-05 1 views
0

J'ai la situation suivante: J'essaie d'implémenter une servlet d'interrogation longue en java (va fonctionner sur jetty). J'utilise AsyncContext et TimerTask pour y parvenir."Le Locker n'est pas réentrant" dans la servlet java java asynchrone long polling

J'ai une classe de session qui a cette méthode:

public boolean setLongPollingContext(final AsyncContext ctx) { 
    if (ctx==null) 
     return false; 
    this.longPollContext = ctx; 

    this.alertHandler = new AlertNotificationHandler() { 
     @Override 
     public void onNewAlert() { 

     } 

     @Override 
     public void onTimeout() { 
      System.out.println("*** timeout ***"); 
      HttpServletResponse response = (HttpServletResponse)ctx.getResponse(); 
      response.setStatus(408); // timeout 
      try { 
       response.getWriter().write("Timeout"); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
      ctx.complete(); 
     } 
    }; 

    this.alertHandler.setTimeout(this.longPollingInterval); // 31 seconds 
    return true; 
} 

(setTimeout commence juste un fil de minuterie qui appelle "onTimeout" en 31 secondes)

J'appelle comme ceci:

final AsyncContext asyncCtx = request.startAsync(request, response); 
session.setLongPollingContext(asyncCtx); 

Cela a fonctionné correctement en moins de 30 secondes (ce qui est, semble-t-il, le délai par défaut du thread ssl/http dans jetty 9.3).

Plus de 30 secondes, je recevais problème lié au délai d'attente que je fixe en réglant cette ligne dans mon Apaisez/start.d/fichier ssl.ini:

## Connector idle timeout in milliseconds 
jetty.ssl.idleTimeout=330000 

Je ne reçois pas le problème de délai d'attente plus , mais maintenant j'ai quelque chose d'encore plus bizarre:

Exception in thread "Timer-0" 
java.lang.IllegalStateException: Locker is not reentrant 
at org.eclipse.jetty.util.thread.Locker.concLock(Locker.java:85) 
at org.eclipse.jetty.util.thread.Locker.lock(Locker.java:61) 
at org.eclipse.jetty.server.HttpChannelState.getStatusString(HttpChannelState.java:166) 
at org.eclipse.jetty.server.HttpChannelState.complete(HttpChannelState.java:481) 
at org.eclipse.jetty.server.AsyncContextState.complete(AsyncContextState.java:92) 
at com.theobroma.paranoidandroid.session.ProxyClientSession$1.onTimeout(ProxyClientSession.java:60) 
at com.theobroma.paranoidandroid.session.AlertNotificationHandler$1.run(AlertNotificationHandler.java:25) 
at java.util.TimerThread.mainLoop(Unknown Source) 
at java.util.TimerThread.run(Unknown Source) 

Google n'a pas réussi à me donner des vecteurs pertinents à ce sujet.

Y a-t-il autre chose que je dois configurer dans la jetée?

est-il un moyen de définir ces options de configuration sans modifier les fichiers de configuration (à partir du code, comme avec annotations ou fixer quelques variables statiques?)

Merci!

+1

Pourquoi implémentez-vous le délai d'attente par vous-même et n'utilisez pas les délais d'attente intégrés dans AsyncContext? –

+0

Eh bien, surtout parce que je voulais être capable de faire des choses sur le timeout. Je ne sais pas si c'est possible avec les built-ins, mais c'était très utile car apparemment le timer intégré était celui qui a expiré et invalidé mon flux de sortie de réponse. Donc régler le timeout à longPollingInterval + quelque chose a résolu le problème, merci! –

+0

Si vous souhaitez en faire une réponse, je peux l'accepter et d'autres personnes peuvent le voir plus facilement :) –

Répondre

0

Joakim Erdfelt m'a donné quelques conseils très utiles que je compilerai dans une réponse, car il résout le problème pour moi.

Donc, il semble que le problème est que l'AsyncContext a son propre délai d'attente qui par défaut 30 secondes sur mon installation (je suppose qu'il n'a rien à voir avec les 30 secondes de jetée, c'était juste une coïncidence trompeuse Une fois le contexte asynchrone expiré, les flux de requête et de réponse sont fermés et ne peuvent pas être ouverts à nouveau, d'où l'erreur.

La solution a été d'augmenter le délai d'attente du contexte async:

ctx.setTimeout(this.longPollingInterval+1000); 

J'ai ajouté un peu de temps supplémentaire pour que pour vous assurer qu'il ne Timeout pas avant mon propre thread de délai d'attente.

Il existe un moyen d'affecter un écouteur pour l'événement timeout au contexte asynchrone. J'y jetterai un coup d'oeil et je l'utiliserai à la place de mon propre thread de timeout. Pourquoi je ne suis pas au courant de Java, donc je ne savais pas à ce sujet :)