2010-03-02 2 views
6

J'ai une situation qui semble correspondre à la situation Async Servlet 3.0/Comet mais tout ce que je dois faire est de renvoyer un code de réponse 200 (ou autre) après avoir accepté les paramètres entrants.Fin d'une réponse HttpServletResponse mais poursuite du traitement

Existe-t-il un moyen pour un HttpServlet de terminer la négociation de la demande/réponse http et de poursuivre le traitement?

Quelque chose comme ...

doPost(req, response) { 
    // verify input params... 
    response.setStatus(SC_OK); 
    response.close(); 
    // execute long query 
}  

EDIT: En regardant le paquet javax.servlet - le phrasé propre à ma question est

Comment puis-je commets une réponse?

comme dans Servlet.isCommitted()

+0

« Engagé » signifie une partie du flux de réponse a déjà été envoyé au client. Il ne peut pas être repris ou modifié.Cela peut se produire dès que vous définissez un en-tête ou écrivez dans la réponse, en théorie, mais généralement les tampons du conteneur arrivent donc un peu plus tard. Ce n'est pas pertinent pour vous, je pense. Ne fermez pas les flux de réponse. Réglez simplement le statut, lancez un thread selon les autres réponses, laissez donePost() finir. –

+0

J'ai essayé d'utiliser response.sendError (SC_OK) mais il n'a toujours pas vidé la réponse au demandeur. Il semble que la seule façon de fermer une requête de servlet est de retourner d'un doPost(). – Stevko

Répondre

6

Voilà comment j'ai manipulé cette situation:

  1. Lorsque l'application démarre, créez un ExecutorService avec Executors.newFixedThreadPool(numThreads) (il existe d'autres types d'exécuteurs, mais je suggère de commencer par celui-ci)
  2. Dans doPost(), créer une instance de Runnable qui effectuera le traitement souhaité - votre tâche - et le soumettre à la ExecutorService comme ceci: executor.execute(task)
  3. Enfin, vous devez retourner le statut HTTP 202 Accepted, et, si possible, un Location En-tête indiquant où un client pourra vérifier l'état du traitement.

Je recommande fortement vous lisez Java Concurrency in Practice, c'est un livre fantastique et très pratique.

+0

Bien que je sois d'accord avec toutes les réponses, celle-ci a le moins de complexité possible. Merci à pajton, beny23 et avi pour votre contribution. – Stevko

+0

comment je fais cela, si je veux utiliser executor.submit() au lieu de .execute? Je veux utiliser. Soumettre pour que je puisse obtenir des «futurs» et savoir quand toutes les tâches sont terminées (sur la base de laquelle je dois effectuer certains traitements?). – Tintin

3

Vous pouvez poursuivre le traitement dans un thread séparé.

La réponse est validée lorsque vous revenez de la méthode doPost().

+0

Je suis en train de courir dans le service URL Fetch 5 sec timeout sur des demandes parfaitement bonnes provenant d'un moteur d'application Google. Le demandeur App Engine ne doit pas bloquer l'attente d'une réponse OK à partir de quelque chose qui peut prendre beaucoup de temps pour terminer le traitement. – Stevko

+0

Ok, donc tout ce dont vous avez besoin est juste un fil de fond :). – pajton

3

Si votre servlet peut accepter une demande de traitement en arrière-plan, la servlet doit transférer le traitement à un thread séparé qui s'exécute ensuite en arrière-plan. En utilisant Spring, vous pouvez appeler un thread séparé à l'aide de la TaskExecutor. L'avantage de l'utilisation du ressort sur JDK 5 java.util.concurrent.Executor standard est que si vous utilisez des threads gérés (IBM websphere ou Oracle weblogic), vous pouvez utiliser le WorkManagerTaskExecutor pour vous connecter aux gestionnaires de travaux CommonJ. Une autre alternative serait de déplacer la logique de requête longue dans un Bean piloté par message ou un POJO piloté par message (Spring JMS peut aider ici) et de laisser le servlet simplement poster un message sur une file d'attente JMS. Cela aurait l'avantage que si la charge de votre conteneur Web devenait trop importante à cause de votre longue requête, vous pourriez facilement déplacer la MDB sur un autre système (dédié).

0

Cet exemple peut aider

void doPost(){ 
    // do something 
    final ExecutorService executor = Executors.newSingleThreadExecutor(); 
     executor.execute(new Runnable() { 
      @Override 
      public void run() { 
       // processing after response 
      } 
     });} 
+1

Pourriez-vous développer cette information? –

+0

Il est préférable de ne pas instancier un ExecutorService chaque fois que la servlet reçoit une requête, sinon vous commencerez à créer beaucoup de threads qui ne meurent jamais, au moins par la documentation newSingleThreadExecutor(). –

Questions connexes