2010-10-06 24 views
5

Il runtime di ASP.NET è pensato per carichi di lavoro brevi che possono essere eseguiti in parallelo. Devo essere in grado di pianificare eventi periodici e attività in background che possono essere eseguite o meno per periodi molto più lunghi.Progettazione di una libreria di task asincrona per ASP.NET

premesso ho i seguenti problemi da affrontare:

  • all'AppDomain può spegnere causa di cambiamenti (Web.config, bin, App_Code, etc.)
  • IIS ricicla AppPool su una regolarmente (ogni giorno)
  • IIS si potrebbe riavviare, o per quella materia il server potrebbe bloccarsi

io non sono convinto che l'esecuzione di questo codice all'interno di ASP.NET non è la cosa giusta da fare, becuase permetterebbe un modello di programmazione più semplice. Tuttavia, fare ciò richiederebbe che un servizio esterno effettui periodicamente richieste all'applicazione in modo che l'applicazione sia in esecuzione e che tutte le attività in background siano programmate con la massima cura. Dovranno essere in grado di mettere in pausa e riprendere il loro lavoro, in caso di errore imprevisto.

mia attuale linea di pensiero più o meno così:

Se tutti i lavori vengono registrati nel database, dovrebbe essere possibile utilizzare il database come un meccanismo di contabilità. Nel caso di un errore, il database conterrà tutti gli stati necessari per riprendere l'operazione alla prossima opportunità data.

Mi piacerebbe davvero dare un po 'di feedback/consigli su questo argomento. Ho preso in considerazione l'esecuzione di un servizio di Windows e l'utilizzo di alcune soluzioni RPC, ma non ha lo stesso appeal per me. Avrei invece avuto un sacco di problemi di distribuzione e attività ricognitive e il codice attraversava diverse applicazioni. A causa delle mie esigenze di lavoro, questo è meno che ottimale.

risposta

4

Questo è uno sparo al buio poiché non so quale database usi, ma ti consiglio di considerare dialog timers e activation. Supponendo che maggior dei posti di lavoro hanno a che fare un po 'di manipolazione dei dati, ed è probabile che tutto hanno a che fare solo manipolazione dei dati, sfruttando l'attivazione e timer dare una soluzione di job scheduling estremamente affidabile, completamente integrato nel database (no è necessario un processo/servizio esterno, non dipendenze esterne ai limiti del database come msdb) ed è una soluzione che garantisce che i processi pianificati possano sopravvivere a riavvii, eventi di failover e persino ripristini di ripristino di emergenza. In poche parole, una volta programmato un lavoro, verrà eseguito anche se il database viene ripristinato una settimana dopo su un altro computer.

Dai un'occhiata a Asynchronous procedure execution per un esempio correlato.

E se questo è troppo radicale, almeno dare un'occhiata a Using Tables as Queues poiché la memorizzazione degli elementi pianificati nel database spesso rientra nel caso di 'coda in attesa'.

+0

+1 per il collegamento all'articolo sull'esecuzione della procedura asincrona. –

+0

Questo è fantastico, sfortunatamente non tutte le attività in background possono essere scritte solo in T-SQL, molte probabilmente potrebbero, ma al momento, abbiamo un supporto per il debug limitato per T-SQL, così come, cose che devono essere in C# codice, come l'invio di e-mail. Inoltre, alcune di queste trasformazioni che facciamo, sembrano davvero scomode in SQL e sono spesso più facili da mantenere usando il codice C#. Sulle tabelle come code, ho fatto qualcosa di simile in passato, ma non ho visto prima queste varianti, grazie per i link. –

+0

L'attivazione può avviare anche le procedure CLR e c'è anche un attivatore esterno che può avviare processi ordinari (.exe): http://blogs.msdn.com/b/sql_service_broker/archive/2008/11/21/announcing- service-broker-external-activator.aspx –

2

Si consiglia di dare un'occhiata a Quartz.Net. È open source e ti darà alcune idee.

+1

Più che darvi qualche idea, farà praticamente esattamente quello che volete. – badbod99

+0

Tranne che non risponde alla mia più grande preoccupazione sulla fattibilità dell'uso di ASP.NET come ambiente di hosting per attività asincrone. Quartz, quanto fantastico possa essere, non aiuterà qui. –

+0

5 anni dopo e qui sto ancora cercando un aspecifico e affidabile pianificazione dei lavori in background con esecuzione asincrona dei lavori –

1

Ti dico quello che ho fatto.

Ho creato una classe chiamata Atzenta con timer (trigger di 1-2 secondi). Ho anche creato una tabella sul mio database temporaneo che mantiene i lavori. La tabella conosce jobID, altri parametri, priorità, stato del lavoro, messaggi.

Posso aggiungere o eliminare un lavoro in questo corso. Quando non c'è azione da fare il timer è fermo. Quando aggiungo un lavoro, il timer ricomincia. (il timer è un thread da solo che può fare il lavoro parallelo). Uso System.Timers and not other timers for this.

I lavori possono avere priorità diversa.

Ora diciamo che ho posto un lavoro su questo tavolo usando la classe Atzenta. La prossima volta che il timer è attivato, controlla la query su questa tabella e trova il primo lavoro disponibile ed eseguilo. Nessun altro lavoro viene eseguito fino alla fine di questo.

Ogni sincronizzazione e flag vengono eseguiti dalla tabella. Nella tabella ho i flag per ogni lavoro che mostra se il suo | wait to run | richiesta di esecuzione | run | pause | finish | killed |

Tutti i lavori sono tutte funzioni o classi note (ad esempio, la creazione di statistiche).

Per l'arresto e l'avvio, utilizzo global.asax e Application_Start, Application_End per avviare e mettere in pausa l'oggetto che mantiene le attività. Ad esempio, quando faccio un lavoro, e ottengo l'etere Application_End, aspetto di terminare e quindi di interrompere l'app, ether interrompo l'azione, comunico alla tabella e ricomincio su application_start.

Quindi dico, Atzenta.RunTheJob (Jobs.StatisticUpdate, ProductID); e poi aggiungo questo lavoro sulla tabella, apro il timer, e quindi su trigger questo lavoro viene eseguito e aggiorno le statistiche per l'id prodotto specificato.

Uso una tabella su un database per sincronizzare molti pool che eseguono la stessa web app e in effetti funziona in questo modo. Con una tabella comune la sincronizzazione dei lavori è semplice e si evitano due pool per eseguire lo stesso lavoro allo stesso tempo.

Sul mio back office ho una semplice vista tabella per vedere lo stato di tutti i lavori.

+0

Mi piace questo, hai avuto problemi relativi all'arresto anomalo dell'app o interrotto in modi imprevisti? –

+0

@John No Non ho problemi particolari. Non spengo il servizio Web, ma apro l'app_offline.htm quando eseguo l'aggiornamento, quindi aspetto di vedere sul mio registro che tutte le applicazioni sono state eseguite, quindi non le obbligherò. Anche il suo non si blocca - se lo trovo lo vedo su log e make try/catch block e così via. Se il processo sul tavolo si è interrotto per qualsiasi motivo, lo capisco dal fatto che lo stato è in esecuzione, ma al momento non eseguo nulla. Il suo flag ancora più semplice salvato sul database che eseguo qualcosa. – Aristos

+0

@John uno dei processi è un indice personalizzato del mio testo sul database. Il primo giorno è stato eseguito per più di 28 ore per completare senza problemi. In seguito correggo un modo in cui posso segnalarlo e mettere in pausa questo indicizzatore. – Aristos

2

L'utilizzo del database come meccanismo di mantenimento dello stato è un'idea completamente valida. Quanto sarà complesso dipende da quanto lontano vuoi prenderlo. In molti casi finirai per associare la logica del tuo database con un servizio Windows per ottenere il risultato desiderato.

FWIW, in genere non è una buona pratica utilizzare manualmente il pool di thread all'interno di un'applicazione ASP.Net, sebbene (contrariamente a quanto si possa leggere) funziona in realtà piuttosto bene oltre all'enorme avvertenza che non è possibile garanzia funzionerà.

Quindi, se avete bisogno di un thread in background che ha esaminato lo stato di alcuni oggetti ogni 30 secondi e non vi è importato se è stato attivato ogni 30 secondi o 29 secondi o 2 minuti (come in un lungo riciclo di app pool), un thread generato da ASP.Net è una soluzione rapida e molto sporca.

Le richiamate in modo asincrono (come nell'oggetto Cache ASP.Net) possono anche eseguire una sorta di ruolo "dietro le quinte".

Ho affrontato sfide simili e alla fine ho optato per un servizio Windows che utilizza una combinazione di elementi costitutivi per la massima flessibilità.Vale a dire, io uso:

1) WCF con i tipi specifici di attuazione o

2) I tipi che hanno lo scopo di trasportare e gestire gli oggetti che avvolgono un lavoro o

3), oggetti serializzabili Completamente generici contenuta in un wrapper personalizzato. Dal momento che sono solo un carico utile binario, questo consente di passare qualsiasi oggetto al servizio. Una volta nel servizio, il wrapper definisce cosa dovrebbe accadere all'oggetto (ad esempio, invoca un metodo, raccogli un risultato e, facoltativamente, rende disponibile quel risultato per il reso).

In definitiva, il sito Web è responsabile dell'interrogazione del servizio sul suo stato. Questa interrogazione può essere semplice come il polling o utilizzare callback asincroni con WCF (anche se credo che usi anche una sorta di polling dietro le quinte).

+0

Grazie per la risposta, sto considerando di serializzare i tipi (invio del codice IL) per l'esecuzione in un ambiente remoto. Se vado con l'approccio al servizio di Windows, allora avrò bisogno di un meccanismo remoto o di invocazione remoto molto flessibile, forse WCF potrebbe facilitare questo, ma ci saranno comunque molte piccole attività che esisteranno solo in certe basi di codice e queste necessitano in qualche modo lavorare con il servizio. –

+0

Ho trovato che le restrizioni DataContract che utilizzano WCF sono difficili da gestire quando è necessario inviare numerosi tipi di oggetti a un servizio per l'esecuzione remota. Ho aggirato questo dichiarando alcuni oggetti wrapper in grado di trasportare i miei alberi degli oggetti (come matrici di byte) e semplici istruzioni su come usare quegli oggetti. Quindi WCF deve solo essere a conoscenza delle interfacce di quegli oggetti wrapper e una delle grandi barriere viene rimossa (IMO). Quando dici "esiste solo in alcune codebase", vuoi dire che l'host di esecuzione non sarebbe in grado di fare riferimento a quei tipi? –

+0

Ovviamente l'host di esecuzione deve essere in grado di fare riferimento a quei tipi, ma non è mai un insieme fisso di cose da fare. Questo varia molto. Sottili ma esistono differenze. Non vedo se stessi creando una serie di servizi che verranno eseguiti per conto di altre applicazioni. –

Problemi correlati