2009-12-30 9 views
8

Qui è il problemaSoluzione al problema di lunga esecuzione di query in un'applicazione web (richiesta asincrona)

Un utente di un'applicazione aziendale web sta eseguendo un compito che si traduce in una lunga (lunghissima) query di database (o altro compito intensiva lunga lavorazione)

Problemi:

  • richiesta scaduta - dopo un po 'l'utente può ottenere un timeout richiesta
  • timeout
  • sessione - se non si utilizzano sessione mantenendo metodi, un ses timeout sione può verificarsi
  • richiesta di blocco filo
    • dal momento che il thread di richiesta non restituisce, potrebbe bloccare i nuovi requrests (se raggiunge il limite piscina)
    • In alcuni server applicativi lo stato di salute del server potrebbe innescare una forzata riavvio del nodo o l'applicazione (a causa di un thread di richiesta lunga esecuzione)
  • Se l'utente lascia la pagina:
    • la transazione non viene annullata - con conseguente trasformazione inutile nessuno beneficerà
    • l'utente non può tornare a vedere i risultati dopo aver completato
  • alcuna indicazione progresso - l'utente appena attende la pagina per aggiornare

Ci sono diverse soluzioni che ho trovato, ma non sono sicuro di sapere quale sia il migliore (in tutti gli aspetti, peformance, best practice, eleganza e manutenibilità) e vorrei sapere qual è la soluzione consigliata, e se c'è una soluzione che mi è sfuggita? (Probabilmente sì, e molti)

La cattiva soluzione: utilizzare il thread di richiesta come un thread di lavoro, salvare lo stato di avanzamento della sessione, hanno un AJAX chiamare verificare lo stato (nella sessione) in un altro richiesta parallela

Il compromesso soluzione: creare il proprio pool di thread, gestire un thread di monitoraggio, un thread di lavoro e prendersi cura di clustering sincronizzazione dei stati in una cache transazionale distrubuted o di stoccaggio persistente. questo rilascia la richiesta, ma crea discussioni che il server delle applicazioni non conosce e non chiuderà in annullamento. Sta a te chiudere i thread in modo pulito, e c'è sempre la possibilità che tu finisca per perdere qualcosa. Questo non è il modo J2EE di farlo neanche.

La soluzione J2EE: utilizzare JMS per l'operazione asincrona, questo è quello che è mento per

la soluzione Primavera: l'uso della molla in lotti

Cosa faresti/fatto nei vostri progetti? Quali altre soluzioni sai? quale di quelli che ho notato sopra è il vincitore secondo te?

risposta

13

vorrei fare una combinazione del vostro cosiddetto "cattiva soluzione" e la "soluzione J2EE":

  1. Il thread UI originale invia un messaggio asincrono JMS al "back-end" e ritorna.
  2. Il backend riceve la richiesta asincrona e la elabora.
  3. Quando viene raggiunto un risultato (o un errore) nel back-end, viene restituito al livello controller.
  4. L'interfaccia utente, che esegue ancora il polling AJAX o utilizza Bayeux/Cometed, riceve e visualizza il risultato.

Il trucco è quello di abbinare la coppia richiesta/risposta. Io farei così:

  1. creare un "AsyncManagerService" (AMS), che ha SESSIONE, forse anche APPLICAZIONE ampio campo di applicazione in modo da tutte le discussioni parlano alla stessa istanza.
  2. L'AMS contiene una mappa con un ID come chiave e qualsiasi oggetto come valore.
  3. Quando si crea il messaggio di richiesta JMS, generare una chiave univoca, casuale e metterlo nella JMSCorrelationID del messaggio così come della mappa, con NULL come valore. Passa anche quell'ID all'interfaccia utente.
  4. Lascia che il thread UI esegua il polling dell'AMS con l'ID precedentemente generato finché il valore nella mappa è NULL.
  5. Quando il risultato è pronto, lasciare che il ricevitore JMS lo inserisca nella mappa AMS all'ID indicato.
  6. La volta successiva che il thread dell'interfaccia utente esegue il polling della mappa, riceverà la risposta e interromperà il polling.

Questo è pulito e ben estratto da qualsiasi dominio concreto. Una soluzione puramente tecnica.

Anche se non ti piace polling, HTTP è stateless in base alla progettazione e credo che in questo modo polling avviene solo intervalli ben definiti.

In ogni caso, ho implementato un sistema con esattamente questo schema e funziona bene ...

+0

Risposta ben scritta, grazie –

+0

@Ehrann: Grazie! Implementalo e fammi sapere se hai una soluzione più fluida ... – raoulsson

1

La soluzione che ho usato prima riguarda Jetty Cometd anziché AJAX.La differenza principale tra Ajax e Cometd è che Cometd può utilizzare più di un modello pub/sub: il client (in questo caso il browser Web) si sottomette al publisher (la tua app) e l'app invia gli aggiornamenti e le notifiche al browser web come apposto a un modello ajax di polling costante del server da parte del browser web. È possibile utilizzare la soluzione Cometd anche se non si utilizza il jetty - è possibile rilasciare i jetty jars nella cartella lib del proprio server Web e si dovrebbe essere a posto.

0

Per quanto tempo sono in esecuzione queste query?

Se si sta parlando di sessioni in scadenza, forse è meglio per l'utente di non essere in attesa intorno per esso. Sarà sempre fastidioso per l'utente aspettare 20 minuti con un picco ogni tanto nella scheda di quella query.

Quindi, se le query veramente lunghe sono il caso, forse è meglio cambiare l'approccio dell'interfaccia utente e fare in modo che l'utente "ordini" una query che lui (lei) in seguito ritorni a vedere, o sia anche notificata per posta quando è pronto.

In tal caso avrei avuto la query preparata nel DB e cache, in una tabella separata, lì. Il che significa che il server Web funzionerà una volta per registrare la richiesta, avere un'attività DB o un processo/server separato per preparare le query su richieste e avvisare l'utente, quindi fare in modo che il server Web le visualizzi quando l'utente torna per risultati.

+0

Questo è coperto da tutte le soluzioni suggerite, ovviamente ci sarà qualche processo del server in background e qualche notifica all'utente. la domanda è quale tecnologia specifica (la tecnologia Java per essere accurata) è la migliore pratica da utilizzare –

+0

@Ehrann: sto suggerendo che la notifica sia "offline" se è un tempo di attesa molto lungo, e sto suggerendo di farlo in un Lavoro DB. –

1

mostrare un messaggio all'utente che "La tua richiesta è accettata e ci vorrà un'ora per ottenere aggiornato"

Si crea una tabella che memorizza tutte queste transazioni e le elabora in un batch sul server.

L'utente non dovrebbe aspettare a lungo e sarà felice di vedere il messaggio. È possibile inviare un'e-mail di conferma una volta che la transazione è stata elaborata.

Questa è la soluzione migliore che penso.

Problemi correlati