2010-03-02 16 views
6

Ho una situazione che sembra adattarsi alla situazione Async Servlet 3.0/Comet, ma tutto ciò che devo fare è restituire un codice di risposta 200 (o altro) dopo aver accettato i parametri in entrata.Finire un HttpServletResponse ma continuare l'elaborazione

C'è un modo per un HttpServlet per completare l'handshake di richiesta/risposta http e continuare l'elaborazione?

Qualcosa di simile ...

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

EDIT: Guardando il pacchetto javax.servlet - il fraseggio giusto per la mia domanda è

Come ho commesso una risposta?

come in Servlet.isCommitted()

+0

"Committed" significa una parte del flusso di risposta è già stato inviato al client. Non può essere ritirato o modificato.Può accadere non appena si imposta un'intestazione o si scrive nella risposta, in teoria, ma di solito i buffer dei contenitori si verificano in un secondo momento. Questo non è rilevante per te, penso. Non chiudere i flussi di risposta. Basta impostare lo stato, avviare un thread come da altre risposte, lasciare che doPost() termini. –

+0

Ho provato a utilizzare response.sendError (SC_OK) ma non ha ancora svuotato la risposta al richiedente. Sembra che l'unico modo per chiudere una richiesta servlet sia restituire da un doPost(). – Stevko

risposta

6

Ecco come ho gestito questa situazione:

  1. Quando l'applicazione si avvia, creare un ExecutorService con Executors.newFixedThreadPool(numThreads) (ci sono altri tipi di esecutori, ma vi suggerisco di iniziare con questo)
  2. In doPost(), creare un'istanza di Runnable che eseguirà il trattamento desiderato - il vostro compito - e lo sottopone al ExecutorService in questo modo: executor.execute(task)
  3. Infine, si dovrebbe restituire lo stato HTTP 202 Accepted, e, se possibile, un Location intestazione che indica dove un cliente sarà in grado di controllare lo stato dell'elaborazione.

ho altamente consiglio di leggere Java Concurrency in Practice, è un libro fantastico e molto pratico.

+0

Mentre sono d'accordo con tutte le risposte, questa ha la minima quantità di complessità coinvolta. Grazie a pajton, beny23 e avi per il tuo contributo. – Stevko

+0

come faccio questo, se voglio usare executor.submit() invece di .execute? Voglio utilizzare .submit in modo da poter accedere ai "futuri" e sapere quando tutte le attività sono state completate (in base alle quali devo eseguire determinate elaborazioni?). – Tintin

3

È possibile continuare l'elaborazione in un thread separato.

La risposta è confermata quando si ritorna dal metodo doPost().

+0

Sto eseguendo il servizio di recupero URL 5 secondi di timeout su richieste perfettamente valide provenienti da un motore di app di Google. Non è necessario che Richiedente di App Engine blocchi l'attesa per la risposta OK da qualcosa che potrebbe impiegare molto tempo per completare l'elaborazione. – Stevko

+0

Ok, quindi tutto ciò di cui hai bisogno è solo un thread in background :). – pajton

3

Sulla possibilità per il servlet di accettare una richiesta per l'elaborazione in background, il servlet deve passare l'elaborazione a una thread separata che viene eseguita in background.

Utilizzando Spring, è possibile richiamare una Filettatura separata utilizzando a a TaskExecutor. Il vantaggio dell'utilizzo della molla rispetto allo standard JDK 5 java.util.concurrent.Executor consiste nel fatto che, se si utilizzano server delle applicazioni che devono utilizzare thread gestiti (IBM websphere o Oracle weblogic), è possibile utilizzare lo WorkManagerTaskExecutor per collegarsi ai gestori lavoro CommonJ.

Un'altra alternativa sarebbe quella di spostare la logica di query lungo in un messaggio Driven Bean o Message Driven POJO (Spring JMS può aiutare qui) e lasciare che il servlet semplicemente inviare un messaggio su una coda JMS. Questo avrebbe il vantaggio che se il carico sul tuo web container diventasse troppo grande a causa della tua query di lunga durata, potresti facilmente spostare MDB su un altro sistema (dedicato).

0

Questo esempio può aiutare

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

Potresti espanderti? –

+0

È meglio non istanziare un ExecutorService ogni volta che il servlet riceve una richiesta, altrimenti inizierete a creare molti thread che non muoiono mai, almeno secondo la documentazione newSingleThreadExecutor(). –

Problemi correlati