Manutenzione di attività in background su un sito di grandi dimensioni


49

Abbiamo a che fare con un problema interessante su StackOverflow.

Abbiamo un sacco di piccoli compiti "da fare presto". Un esempio è l'aggiornamento degli elenchi "Domande correlate". Ciò che abbiamo fatto in passato è riportare queste attività sui carichi di pagina di alcuni utenti.

Questo non è mai stato l'ideale, ma non era davvero evidente. Ora che SO ha superato i 1.000.000 di punti interrogativi, quegli utenti sfortunati stanno iniziando a sentirlo.

La soluzione naturale è quella di spingere effettivamente queste attività in background. Ci sto prendendo in considerazione due modi per farlo.

1. In IIS come pool di thread / coda di lavoro personalizzati

Fondamentalmente, creiamo alcuni thread (non ThreadPool , in modo da non interferire con IIS) e disponiamo di servizi in alcune raccolte in cui stiamo inserendo Funcs .

Il grande professionista qui è la semplicità. Non dobbiamo preoccuparci di fare il marshalling di nulla, né dobbiamo assicurarci che alcuni servizi esterni siano attivi e rispondano.

Abbiamo anche accesso a tutto il nostro codice comune.

La contro è, beh, che non dovremmo usare i thread in background. Le obiezioni che conosco sono tutte incentrate su IIS affamato (se si utilizza ThreadPool) e sui thread che muoiono casualmente (a causa del riciclo di AppPool).

Abbiamo un'infrastruttura esistente per rendere la morte casuale dei thread un problema (in pratica è possibile rilevare un'attività è stata abbandonata) e neanche limitare il numero di thread (e l'utilizzo di thread non ThreadPool).

Mi mancano altre obiezioni nel processo di pool di thread / code di lavoro di IIS?

Spostato in StackOverflow , in quanto non è stato realmente affrontato qui.

2. Come servizio

Qualche soluzione di terze parti o personalizzata.

Fondamentalmente, eseguiremmo un task oltre il limite del processo per alcuni servizi e ci dimenticheremmo. Presumibilmente stiamo collegando del codice o limitato a SQL + grezzo una stringa di connessione.

Il pro è che è il "modo giusto" per farlo.

I contro sono che o siamo molto limitati in ciò che possiamo fare, o dovremo elaborare un sistema per mantenere questo servizio sincronizzato con la nostra base di codice. Dovremo anche collegare in qualche modo tutto il nostro monitoraggio e la registrazione degli errori, che otteniamo gratuitamente con l'opzione "In IIS".

Ci sono altri vantaggi o problemi con l'approccio del servizio?

In breve, ci sono problemi imprevisti e insormontabili che rendono impraticabile l'approccio n. 1 e, in caso affermativo, ci sono buoni servizi di terze parti che dovremmo esaminare per l'approccio n. 2?


Il modo giusto è il modo in cui quando decidi di andare dall'altra parte guardi indietro e dici che avremmo dovuto farlo nel modo giusto. Scegliere saggiamente. Non ho abbastanza familiarità con il mondo IIS per commentare questo particolare problema.
Chris,

2
Sono curioso perché ho uno scenario simile (su una scala molto più piccola) e anch'io sto solo appoggiando le spalle su alcuni sfortunati utenti casuali di connessione. Non ho familiarità con la soluzione migliore, quindi seguirò qui. :-)
pc1oad1etter il

7
Non capisco perché questo non sia su StackOverflow. Questo è un compromesso ingegneristico, non una valutazione soggettiva. Stai chiedendo un'analisi dei diversi approcci - è tutto oggettivo. Solo quando l'analisi ha chiarito quali sono esattamente i compromessi, c'è soggettività ad esso, e per quanto posso vedere la tua domanda non è 'cosa dovrei trovare più importante, il mio tempo e le risorse del server o il tempo del mio utente? ' o qualcosa di simile.
Joren,

@ Kevin Montrose - dai tuoi commenti, sembra che tu stia facendo una distinzione tra "deve essere fatto presto" e "programmato su un intervallo". Puoi approfondire il motivo per cui questi sono due diversi tipi di attività in background che richiedono un modello / infrastruttura differente?
Portman,

@Portman - La differenza fondamentale è che i compiti "presto" non possono essere svolti in modo speculativo, dobbiamo davvero aspettare fino a quando sappiamo che devono essere fatti. Alcuni calcoli sul retro della busta mostrano che se dovessimo spostare le query "Domande correlate" (solo una delle tante) in una scheda cron "stupida", occorrerebbero circa. una settimana di solida esecuzione per rispondere a tutte le domande. In generale vorremmo anche che fossero eseguiti il ​​più presto possibile (senza influire sull'esperienza dell'utente), mentre le nostre attività a intervalli possono essere eseguite eseguendo non più frequentemente di una volta in 5 minuti (e normalmente molto meno frequentemente).
Kevin Montrose

Risposte:


17

Qualche settimana fa ho fatto una domanda simile su SO. In poche parole, il mio approccio da qualche tempo è stato quello di sviluppare un servizio di Windows. Vorrei utilizzare NServiceBus (essenzialmente MSMQ sotto le coperte) per eseguire il marshalling delle richieste dalla mia app Web al mio servizio. Usavo WCF ma ottenere una transazione distribuita per funzionare correttamente su WCF mi è sempre sembrato una seccatura. NServiceBus ha fatto il trucco, potevo eseguire il commit dei dati e creare attività in una transazione e non preoccuparmi se il mio servizio fosse attivo e funzionante in quel momento. Come semplice esempio, se mai avessi bisogno di inviare un'e-mail (ad esempio un'e-mail di registrazione), avrei creato l'account utente e lanciato un segnale al mio servizio Windows (per inviare l'e-mail) in una transazione. Il gestore dei messaggi sul lato servizio preleva il messaggio e lo elabora di conseguenza.

Dal momento che ASP .NET 4.0 e AppFabric sono stati rilasciati, esistono diverse alternative valide al meccanismo sopra. Facendo riferimento alla domanda che ho menzionato sopra, ora abbiamo AppInitialize di AppFabric (via net.pipe) e la funzione di avvio automatico di ASP .NET 4.0 che rende lo sviluppo di servizi Windows come app Web un'alternativa praticabile. Ho iniziato a farlo ora per una serie di motivi (il più grande è lo spiegamento non è più un dolore nel culo):

  1. È possibile sviluppare un'interfaccia utente Web tramite il servizio (poiché è in esecuzione come app Web). Questo è estremamente utile per vedere cosa sta succedendo in fase di esecuzione.
  2. Il modello di distribuzione per le app Web funzionerà per l'applicazione di servizio.
  3. IIS offre alcune funzionalità precise per la gestione degli errori delle applicazioni (simile per alcuni aspetti a un servizio Windows).
  4. Gli sviluppatori Web hanno familiarità con lo sviluppo di app Web (naturalmente), la maggior parte non conosce molto le migliori pratiche durante lo sviluppo di un servizio Windows.
  5. Fornisce una serie di alternative all'esposizione di un'API da utilizzare per altre app.

Se segui questa strada (perdonami per aver copiato e incollato il mio post originale), prenderei sicuramente in considerazione l'esecuzione della logica di background in un'applicazione web separata. Ci sono diversi motivi per questo:

  1. Sicurezza . Potrebbe esserci un modello di sicurezza diverso per l'interfaccia utente che visualizza informazioni sui processi in background in esecuzione. Non vorrei esporre questa UI a nessun altro, tranne al team operativo. Inoltre, l'applicazione Web può essere eseguita come un altro utente con un set elevato di autorizzazioni.
  2. Manutenzione . Sarebbe bello poter implementare le modifiche all'applicazione che ospita i processi in background senza influire sull'utilizzo del sito Web front-end da parte dell'utente.
  3. Prestazioni . La separazione dell'applicazione dal sito principale che elabora le richieste dell'utente significa che i thread in background non diminuiranno la capacità di IIS di gestire la coda di richieste in entrata. Inoltre, l'applicazione che elabora le attività in background potrebbe essere distribuita su un server separato, se necessario.

In questo modo si torna all'aspetto marshalling. WCF, NServiceBus / RabbitMQ / ActiveMQ ecc., MSMQ vaniglia, API RESTful (pensa MVC) sono tutte opzioni. Se si utilizza Windows Workflow 4.0, è possibile esporre un endpoint host che potrebbe essere utilizzato dall'app Web.

L'approccio di web hosting per i servizi è ancora abbastanza nuovo per me, solo il tempo dirà se è stata la scelta giusta. Però fin qui è andato tutto bene. A proposito, se non vuoi usare AppFabric (non potrei perché per qualche bizzarro motivo, Windows Server Web Edition non è supportato), la funzionalità di avvio automatico menzionata nel post del Gu funziona bene. Stare lontano dal file applicationhost.config, tutto in quel post è possibile impostare tramite la console IIS (Configuration Editor a livello del server principale).

Nota: originariamente avevo postato qualche altro link in questo messaggio, ma purtroppo, questo è il mio primo post in questo scambio e solo un link è supportato! Ce n'erano praticamente altri due, per farli diventare Google "Death to Windows Services ... Long Live AppFabric!" e "auto-start-asp-net-applicazioni". Mi dispiace per quello.


L'idea di base di utilizzare un sito Web separato come servizio è intrigante che non avevo considerato ...
Kevin Montrose

Rohland, potrei mancare qualcosa qui, ma sembra che tu stia interagendo con un servizio Windows dall'interno del tuo gestore NServiceBus, il servizio quindi invia l'e-mail. Se ho ragione, posso chiederti perché non invii l'e-mail da un gestore di messaggi NServiceBus, che sarebbe molto facile da sviluppare, testare e distribuire?
Sean Kearon,

Il sito Web invia un messaggio al servizio Windows. Il gestore messaggi NServiceBus del servizio Windows preleva il messaggio e invia il messaggio. In sostanza, è lo stesso del processo che stai descrivendo.
Rohland,

22

In realtà esiste un terzo modo in Windows per eseguire servizi in background, ed è molto comune nel mondo UNIX. Il terzo modo è un CRONlavoro che esegue una parte della tua infrastruttura. In Windows questo è noto come task schedulered è molto comune per l'esecuzione di codice su base pianificata. Per usarlo, creare un'app da riga di comando che viene eseguita in base a una pianificazione predefinita. Il vantaggio di questo è che non devi preoccuparti se il processo rimane attivo e funzionante come un servizio, perché se fallisce per qualche motivo, si avvierà la prossima volta.

Per quanto riguarda il marshalling di attività specifiche, è sufficiente memorizzarle in una memoria binaria persistente. Fino a quando l'app della riga di comando non li estrae dall'archivio e li esegue. In passato l'ho fatto utilizzando il database Cassandra come provider dello stato della sessione per riempire le attività in background per utenti specifici nel database Cassandra, e quindi avere la riga di comando selezionarli ed eseguirli per l'utente.

Questa potrebbe non essere stata la tipica soluzione di marshalling, ma ha funzionato molto bene per me e si è rivelata una soluzione molto elegante, perché le attività pianificate sono sopravvissute a arresti, problemi di rete e qualsiasi macchina poteva eseguire l'attività poiché era centralizzata immagazzinato.

Promozione senza vergogna, ma questo è il mio progetto e la soluzione che ho appena brevemente dettagliato è il motivo per cui ho creato il progetto: http://github.com/managedfusion/fluentcassandra/


2
Lo faccio con il mio servizio di hosting condiviso poiché non ho accesso alla shell. Scrivi una pagina PHP che fa qualcosa di importante, quindi fai un cron job che carica periodicamente la pagina usando wget o lynx. Sembra esattamente il tipo di cosa che funzionerebbe in questo caso ed essere estremamente semplice, difficilmente richiede un cambiamento nel modo in cui le cose sono attualmente fatte.
Ricket,

Che soluzione semplice. Ha scatenato idee per il mio progetto che non stavo ancora prendendo in considerazione. Inoltre hai pieno accesso alla tua base di codice esistente. Basta aggiungere un progetto console alla soluzione e fare riferimento ai progetti esistenti.
Tim Murphy,

10

Cron + Web App

Questo è un design testato in battaglia che si ridimensiona orizzontalmente insieme alla tua web farm e ti assicura di utilizzare lo stack della tecnologia web che già conosci.

Ecco come funziona:

  1. Creare un controller / azione nell'applicazione Web per gestire le attività in background pianificate. Per convenzione, di solito chiamo il mio http://mydomain.com/system/cron.
  2. Per motivi di sicurezza, questa azione deve essere bloccata solo agli indirizzi IP autenticati sulla rete locale.
  3. Su una macchina separata, installa Wget e imposta un'attività pianificata per fare in modo che wget recuperi la risorsa dal passaggio 1. Puoi eseguire l'attività con la frequenza che desideri (di solito opto per 30 secondi). Non dimenticare di passare l'argomento cookie appropriato a Wget in modo che si autentichi sulla tua app web.
  4. Per ridondanza, è anche possibile installare una seconda wget programmata su una seconda macchina.

Evviva! Ora hai un percorso che verrà chiamato ogni 30 secondi. E se l'elaborazione della richiesta richiede 5 minuti, a nessuno importa, perché non fa parte della richiesta della pagina di un utente.

L' cronazione sembra molto semplice: ha un elenco di metodi da eseguire su una certa frequenza. Quando arriva una richiesta, vede se c'è un metodo che deve essere eseguito e chiama il metodo appropriato. Ciò significa che puoi controllare la pianificazione nel tuo database , dove probabilmente hai già molti altri importanti dati di configurazione per il tuo sito.

Ancora più importante (per te), ciò significa che i tuoi lavori non devono essere chiamati con un programma fisso. È possibile scrivere qualsiasi logica desiderata per determinare quando eseguire un metodo.

Pro e contro

Professionisti
  • Sei già molto bravo a scrivere il codice ASP.NET MVC, quindi questo ti consente di scrivere le tue attività in background nella stessa piattaforma in cui scrivi il resto della soluzione.
  • Le attività vengono eseguite nello stesso contesto dell'app Web, quindi è possibile condividere la cache e utilizzare i metodi di supporto già esistenti.
  • Se hai wget per recuperare un URI con bilanciamento del carico , allora anche le tue attività in background sono bilanciate con il carico.
  • Distribuzione simultanea : non devi preoccuparti di sincronizzare l'app Web con la logica dell'attività in background, poiché sono tutti nella stessa distribuzione.
Contro
  • Nel corso degli anni, alcune persone mi hanno detto che questo design è "altamente accoppiato", ma quando premuto non sono stati in grado di articolare il motivo per cui questa è una brutta cosa.

Nota: in caso di domande o dubbi, aggiungere un commento . Sono felice di elaborare.


7

Ho provato e usato praticamente tutti i modi possibili per farlo nella mia attuale applicazione. Ho iniziato facendo la stessa cosa che fai attualmente, salvando una richiesta dell'utente per riempire i dati e poi memorizzarli nella cache in futuro. Mi sono reso conto che anche questa è stata una cattiva idea (specialmente se si passa a più server Web, più utenti subiscono il colpo).

Ho anche avuto un lavoro programmato che colpisce un URL nell'app ASP.NET: questa è una soluzione decente ma inizia a rompere il minuto che passi oltre 1 web server.

Attualmente uso due metodi diversi, entrambi usando Quartz.NET che è una piccola libreria fantastica. Il primo è Quartz.NET in esecuzione con ASP.NET, è installato in global.asax e viene eseguito ogni paio di minuti. Lo uso per aggiornare la cache ASP.NET fuori banda, che è l'unica ragione per cui viene eseguita come parte di ASP.NET.

Il secondo è che ho scritto una libreria per racchiudere Quartz.NET chiamato DaemonMaster: è facile rilasciare una DLL in una directory e farla funzionare in un servizio Windows. Ho scoperto che aiuta ad evitare alcune delle parti fastidiose di lavorare con un servizio di Windows e pulisce anche alcune API Quartz.NET. I servizi che eseguono DaemonMaster sono di due tipi diversi, i primi sono i lavori che devono essere eseguiti ogni notte o ogni minuto X. Gli altri lavori funzionano fuori da una coda in base ai dati provenienti dall'applicazione ASP.NET. L'app ASP.NET rilascia oggetti JSON su RabbitMQ e il polling dei servizi RabbitMQ quindi elabora i dati.

In base a questo, ti suggerirei di andare con un servizio Windows (e controllare DaemonMaster) e, se necessario, utilizzare una coda come RabbitMQ per passare i dati dall'app ASP.NET ai servizi - ha funzionato al meglio con tutte queste soluzioni . Se si sta caricando la cache, l'esecuzione in ASP.NET ha senso, altrimenti non penso che lo sia.


6

Lo farei nel modo giusto e avrei un servizio Windows in esecuzione che controlla una "coda". Dico "coda" perché la programmazione con MSMQ è simile a quella dei poker caldi nei tuoi occhi.

Mi sono innamorato della semplicità di Delayed :: Job in Rails e qualcosa di simile potrebbe essere facilmente fatto in .NET.

Fondamentalmente aggiungi qualsiasi tipo di SomethingOperation(qualcosa che ha un Perform()metodo). Quindi serializza i parametri pertinenti, assegnagli una priorità, una sorta di comportamento di prova predefinito e inseriscilo in un database.

Il vostro servizio lo monitorerebbe e lavorerebbe i lavori in coda.


La serializzazione dei parametri rilevanti non è in realtà un "giusto", è quasi il "tutto". È una delle mie maggiori riserve sull'approccio del processo separato ...
Kevin Montrose

Sì, è una specie della stessa soluzione che ho usato, tuttavia ho serializzato l'intero oggetto nel database come binario e poi li ho estratti per eseguirli. Ho usato Cassandra come memoria permanente e Utilità di pianificazione come pianificatore CRON per l'app a riga di comando che avrebbe eseguito ed eseguito le attività.
Nick Berardi,

Abbiamo iniziato includendo solo un semplice dato nel messaggio e finendo per lanciare l'intero oggetto. Funzionava ancora alla grande. Considererei la separazione in quanto ha anche altri vantaggi.
Nathan Palmer,

@Kevin - se solo avessimo avuto alcune persone con molta storia di serializzazione ....
Marc Gravell

4

Siamo rimasti piuttosto soddisfatti dell'approccio Bus di servizio / Coda messaggi / Servizio. L'architettura di base è questa.

Il sito Web invia un messaggio in coda

bus.Send(new ProjectApproved()); // returns immediately

Il servizio Windows riceve ed elabora i messaggi a suo tempo

public class DoesSomethingAwesome : ConsumerOf<ProjectApproved>
{
   public void Consume(ProjectApproved Message)
   {
      // Do something "offline"
   }
}

Il vantaggio è che non vi è alcun ritardo per il servizio front-end a cui sono connessi anche gli utenti. Il servizio Windows può essere arrestato ed aggiornato senza interruzione al sito principale. Inoltre è estremamente veloce .

Se non è possibile memorizzare tutti i dati all'interno del messaggio, è sempre possibile archiviarli e recuperarli in un secondo momento. Suggerisco di utilizzare un meccanismo di archiviazione dei documenti come: RavenDB o MongoDB, dove è molto semplice archiviare le lezioni senza modifiche.

Il sito Web invia un messaggio in coda

// Save your object
store.Save(completeProject);

// Send a message indicating its ready to be processed
bus.Send(new ProjectApproved() { ProjectId = completeProject.Id });

Il servizio Windows riceve ed elabora i messaggi a suo tempo

public class DoesSomethingAwesome : ConsumerOf<ProjectApproved>
{
   public void Consume(ProjectApproved Message)
   {
      // Retrieve your object back
      var completeProject = store.Get(Message.ProjectId);
   }
}

Per semplificare le cose usiamo: Rhino ESB e Topshelf . La configurazione è estremamente semplice e metterla in atto per un'applicazione esistente ha dimostrato di richiedere pochissimo tempo.


Ad ogni modo, l'uso di un bus di servizio con CQRS è sempre un buon modo per migliorare la tua scalabilità
thinkbeforecoding

3

Sono curioso di sapere perché una combinazione dei due non è un'opzione praticabile. In questo momento attivi processi nelle visualizzazioni di pagina, con qualche sfortunata linfa che si blocca in attesa di 10 secondi prima che la pagina venga visualizzata. Almeno questa è la mia comprensione del tuo metodo attuale.

Tuttavia, questi lavori impiegano sempre più tempo a funzionare man mano che il sito cresce e non si desidera far deragliare l'esperienza dell'utente sul sito. Nemmeno per pochi (o forse molti) utenti sfortunati per tutto il giorno, quindi ora stai pensando di pianificare i lavori in background.

Non vedo perché un lavoro in background eseguito a intervalli regolari non possa imitare un visitatore. Ora non sono un programmatore di Windows, ma nel mondo Linux avrei impostato un lavoro cron che viene eseguito a intervalli regolari e avrebbe 2 righe di codice.

#!/bin/bash
wget -O /dev/null http://stackoverflow.com/specially_crafted_url

Unisce i vantaggi di entrambi i sistemi. È fatto in background. Non influisce sugli utenti. Utilizza ancora una visualizzazione di pagina per dare il via al lavoro. Ho visto questo approccio usato prima. Tende ad essere la via di mezzo tra i semplici modi del vecchio e i modi più complessi che scendono lungo la strada.

Aggiornare

Penso che sia possibile aggirare il problema del bilanciamento del carico eseguendo i corridori di lavoro sui server Web stessi. Il job runner estrae un URL dalla coda dei lavori e lo esegue in questo modo:

wget -O /dev/null http://localhost/specially_crafted_url

A causa della natura delle code di lavoro / messaggistica, i lavori verranno distribuiti uniformemente tra i corridori di lavoro, il che significa che alla fine viene distribuito appositamente_crafted_url tra i server Web.


Lo facciamo già per tutto ciò che funziona a intervalli prevedibili, ciò che ci rimane sono cose che non possono essere previste con largo anticipo. Ad esempio, il "blocco di domande correlate" viene aggiornato solo sulle domande che sono state visualizzate di recente. Anche gli elenchi di domande con tag vengono memorizzati nella cache solo se a qualcuno interessa controllare tali tag. Poiché abbiamo oltre un milione di domande e ci avviciniamo ai tag 25k non possiamo eseguire tutte le attività associate (e questo è solo 2 esempi) "per ogni evenienza".
Kevin Montrose

Esistono anche problemi di bilanciamento del carico, in quanto SO è suddiviso su più server. Fondamentalmente, se vai su stackoverflow.com, colpirai sempre lo stesso server. L'approccio wget ci costringerebbe a eseguire il marshalling di tutte le attività su un singolo server (o davvero rielaborare la nostra configurazione di bilanciamento del carico), il che sarebbe davvero doloroso.
Kevin Montrose

Sii gentile se le cose andassero a intervalli regolari, eh? Capisco quello che stai dicendo, ma la metodologia descritta sopra (e penso che sia menzionata da poche altre persone) non cambia. Quando una vista di pagina dice "è ora di eseguire questo lavoro", si inserisce il lavoro in una coda di messaggi. Un lavoro in background di lunga durata esegue i lavori che trova. In questo caso i lavori non sono altro che URL che devono essere richiesti. hehe Probabilmente potresti configurarlo su un server condiviso da $ 20 al mese, poiché non ha bisogno della tua base di codice per funzionare. Dai un'occhiata ad Amazon SQS per un servizio di messaggistica facile da usare.
Mellowsoon,

Per quanto riguarda i problemi di bilanciamento del carico. Dove c'è una volontà, c'è un modo! Invece di fare la richiesta a stackoverflow.com, potresti colpire un server a caso usando il suo indirizzo IP. Se il bilanciamento del carico controlla i cookie per reindirizzare le richieste, è possibile falsificare i cookie. Se controlla l'indirizzo IP, probabilmente potresti persino falsificarlo (poiché non ti interessa la risposta dal server).
Mellowsoon,

Concordato che il bilanciamento del carico non dovrebbe essere un motivo per non farlo. Poiché la richiesta specially_crafted_urlproviene da un IP noto, è possibile aggiungere una regola sul bilanciamento del carico per eseguire il round robin solo per le richieste provenienti da tale IP.
Portman,

2

Penso che il truffatore con il puro approccio al servizio sia che hai il codice sparso nel servizio e lontano dall'app principale.

Ecco cosa abbiamo fatto con grandi lavori in background non sensibili al tempo, che tengono insieme il codice e semplificano il servizio:

  1. Creare una coda lavori (in memoria o DB, qualunque persistenza sia necessaria per i tipi di lavori)
  2. Creare un servizio Web che eseguirà i lavori in coda
  3. L'app di servizio semplice morta che chiama il servizio Web a un intervallo specificato, lascia tutte le cose complesse (recupero ed esecuzione dei lavori) al servizio Web nella base di codice principale.

Ancora più semplice, basta effettuare la chiamata in un'app console e utilizzare Task Scheduler o VisualCron per trasformarlo in un "servizio".


1
Ho esattamente questo in una significativa applicazione al lavoro - un servizio di Windows che attiva l'app Web a intervalli. L'app Web rimane senza stato, estraendo lo stato dal database come richiesto. Funziona a meraviglia.
Bevan,

1

Mi è piaciuto TopShelf. Mantiene la semplicità, ma lo fa ancora nel modo corretto in esecuzione come un servizio di Windows. Fondamentalmente creare un'app console, aggiungere circa 15-20 righe di codice, quindi si installa come servizio.

http://code.google.com/p/topshelf/


1

Che ne dici di avere un servizio Windows molto semplice che gira sul web server e colpisce periodicamente un URL di manutenzione che fa le tue varie attività. Fai rallentare la quantità di lavoro che svolge in una determinata richiesta.


1

Ho intenzione di invertire la tendenza apparente qui e suggerire di scegliere il modello in-IIS. L'ho usato da solo e funziona davvero bene. Realizzare una classe di pool di thread decente non è poi così difficile (nel corso degli anni ho ampliato la mia classe di pool di thread per supportare la creazione dinamica e la distruzione di thread, i tentativi di lavoro e così via). I vantaggi sono:

  • Nessun servizio esterno da monitorare
  • Semplicità di implementazione: nessun marshalling tra processi, nessun monitoraggio avanzato dei lavori
  • Sei ancora all'interno del tuo processo IIS, quindi puoi fare tutto il tuo solito log e così via (non sono necessari più file di registro)
  • Implementazione notevolmente semplificata (quando si aggiorna un servizio, è necessario interrompere il servizio, copiare i file, avviare il servizio - questo è in aggiunta ai soliti aggiornamenti del codice del sito Web)

A mio avviso, una soluzione in-IIS è semplicemente il "passo successivo" dal portare il lavoro su visualizzazioni di pagina casuali.


1

Resque è carino. O anche Kthxbye se devi essere avvisato del valore risultante una volta completato.

Entrambi basati su Redis / Ruby.

Onestamente, se stai adottando un approccio basato sui servizi, in realtà non ha bisogno di essere super integrato con la tua piattaforma attuale, che ritengo sia un vantaggio. Spero che possa essere un sistema set-and-forget in grado di funzionare (con un monitoraggio di qualche tipo) e completare i lavori. Non sono sicuro che debba essere eseguito sulla stessa piattaforma dal momento che sta semplicemente aggiornando / modificando le informazioni del database.

Abbastanza sicuro che potresti ottenere molto di più per molto di meno se hai coltivato questo tipo di lavoro in un'entità separata, soprattutto perché sembra che tu abbia a che fare con problemi di threading. Sia Resque che Kthxbye spostano l'elaborazione in processi separati per consentire al sistema operativo di gestire la concorrenza.

Resque

Kthxbye


Devo provare Kthxbye se non altro per il grande nome!
Nathan Palmer,

praticamente il fantastico. il prossimo sarà l'ORLY? biblioteca. probabilmente per il monitoraggio delle statistiche di qualche tipo ...;)
Lukas

0

Vorrei utilizzare un servizio WCF ospitato WAS ascoltando una coda MSMQ.

Professionisti

  • Spara e dimentica i messaggi a senso unico dall'app Web

  • Limitazione e riprovare di MSMQ / WCF

  • Consegna garantita; D

  • Gestione della lettera morta

  • Elaborazione distribuita

  • Attivazione WAS / MSMQ

di Con

  • MSMQ (non è morto ... ancora)

Le funzionalità MSMQ in WCF rendono davvero piacevole l'utilizzo di MSMQ. Sì, sanguinerai sulla configurazione ma i benefici supereranno il sacrificio.


0

Mi sono imbattuto in questo un paio di volte durante lo sviluppo di applicazioni web. Lo abbiamo risolto creando un'applicazione console Windows che esegue l'attività e creando un'attività pianificata che viene eseguita ogni tanto per svolgere effettivamente l'attività.


0

Puoi spostare il lavoro su un thread in background (o su molti thread in background) usando Rx e qualcosa di simile al seguente:

var scheduler = new EventLoopScheduler( SchedulerThreadName );
_workToDo = new Subject<Action>();
var queueSubscription = _workToDo.ObserveOn( scheduler ).Subscribe( work => work() );
_cleanup = new CompositeDisposable( queueSubscription, scheduler );

Usare:

var work = () => { ... };
_workToDo.OnNext( work ); // Can also put on error / on complete in here

Ospita tutto ciò all'interno di una classe di cui esiste una sola (nota anche come singleton, ma fallo correttamente - usa il tuo contenitore IoC per determinare lo stile di vita).

È possibile controllare le dimensioni del pool di thread, ecc. Scrivendo uno scheduler personalizzato anziché utilizzare EventLoopScheduler (che esegue un singolo thread).


0

Ho implementato questo tipo di cose alcune volte. Su Windows, ho impostato un programma da riga di comando Python che fa qualcosa in varie occasioni. Questo programma espone anche un'interfaccia xmlrpc su una porta. Quindi, un processo pianificato viene eseguito ogni minuto e richiede le interfacce xmlrpc. Se non sono attivi, tenta di avviarli. Se non può, mi manda una email.

Il vantaggio è che il lavoro che viene eseguito non è associato a cron o pianificazione. Ho un processo che viene eseguito ogni secondo, ma aspetterò sempre più a lungo tra l'avvio di un nuovo lavoro a seconda che avesse del lavoro da fare. Inoltre, può essere utilizzato per agire in modo intelligente in base al risultato. Hai un errore 500? Hai un ritardo davvero lungo? Fai qualcos'altro. Notifica un altro servizio. Eccetera.

E lo stesso sistema funziona su unix, con piccole modifiche.


0

Non ho una risposta per te stesso, ma il problema ha suonato un campanello - Ricordo alcuni ragazzi a caso che ne discutevano su un podcast una volta .

Spolsky: ho notato che una delle domande che hai posto sul blog era come gestire le attività ricorrenti di manutenzione in generale?

Atwood: Sì.

Spolsky: è una buona caratterizzazione? Ogni sito Web ha alcune attività che non si desidera eseguire al momento del caricamento di una pagina Web, ma che si desidera eseguire con una certa ricorrenza di qualche tipo.

Atwood: Ya, attività in background una sorta di cosa.

Spolsky: Ya, quindi cosa hai capito?

Atwood: Beh, inizialmente l'ho chiesto su Twitter, perché volevo solo qualcosa di leggero. Non volevo davvero scrivere un servizio Windows. Mi sembrava che fosse fuori dal codice della band. Inoltre il codice che svolge effettivamente il lavoro è in realtà una pagina Web, perché per me che è un'unità logica di lavoro su un sito Web è una pagina Web. Quindi, è davvero come se stessimo richiamando il sito Web, è proprio come un'altra richiesta nel sito Web, quindi l'ho visto come qualcosa che dovrebbe rimanere in linea e il piccolo approccio che ci è venuto in mente che mi è stato consigliato su Twitter era essenzialmente quello di aggiungere qualcosa alla cache dell'applicazione con una scadenza fissa, quindi hai una richiamata, quindi quando scade, chiama una determinata funzione che fa il lavoro, quindi la aggiungi nuovamente alla cache con la stessa scadenza.


1
Sì, funziona per siti molto più piccoli di quanto StackOverflow è diventato. La scala è un grosso problema qui, sfortunatamente (o per fortuna, a seconda di come la vedi).
Kevin Montrose

@ Kevin Montrose, supplico qui l'ignoranza completa del dominio. Potresti spiegare perché avere una pagina Web segreta (s) esegue il lavoro (forse in piccole unità) ed essere chiamato da una pagina / cron lavoro rinfrescante da qualche altra parte non è scalabile? Non dubito che tu abbia ragione, ma mi piacerebbe imparare.
Pensando in modo strano il

il tuo suggerimento particolare (quello di scadenza della cache) non viene ridimensionato perché tutte le scadenze della cache (in ASP.NET) eseguono un singolo thread (è un trucco intelligente per siti più piccoli, come una volta SO). Un'attività cron non si ridimensiona perché abbiamo superato un singolo server (SO ora è 3 e continua a crescere) e qualsiasi attività cron colpirebbe un singolo server (almeno, cambiare quell'invariante sarebbe davvero doloroso con il nostro carico- impostazione del bilanciamento). Un'attività cron dovrebbe anche essere eseguita molto frequentemente, poiché queste attività si ripetono nell'ordine dei minuti.
Kevin Montrose

Vale la pena notare che utilizziamo la pianificazione "cron style" per l'esecuzione meno frequente, l'intervallo fisso, le attività già, cose come la concessione di badge e gli avvisi di posta elettronica giornalieri.
Kevin Montrose

0

Panoramica dell'API Java della coda attività

Concetti relativi
all'attività Nell'elaborazione in background di App Engine, un'attività è una descrizione completa di una piccola unità di lavoro. Questa descrizione è composta da due parti:

  • Un payload di dati che parametrizza l'attività.
  • Codice che implementa l'attività.

Compiti come hook Web offline
Fortunatamente, Internet fornisce già una soluzione del genere, sotto forma di una richiesta HTTP e della sua risposta. Il payload dei dati è il contenuto della richiesta HTTP, ad esempio variabili del modulo Web, XML, JSON o dati binari codificati. Il riferimento al codice è l'URL stesso; il codice effettivo è qualunque logica il server esegua nel preparare la risposta.


Non sto suggerendo di utilizzare l'API della coda attività GAE, ma seguendo il loro modello. Ci hanno pensato per un po 'e ne hanno scritto un'implementazione.
antony.trupe,

0

Fai entrambi

Aggiungi un parametro facoltativo al percorso della domanda che svolge il lavoro che stai attualmente trasferendo sulle richieste dell'utente:

Manutenzione di attività in background su un sito di grandi dimensioni

Crea un'app console che viene eseguita su ciascun server e apre il file binario condiviso del registro IIS e lo legge fino alla fine corrente del file. Utilizzare un filesystemwatcher o un intervallo temporizzato per leggere in avanti per raccogliere gli aggiornamenti mentre IIS scaricava il registro.

Utilizzare queste informazioni per determinare quali pagine sono state attualmente visualizzate.

Utilizzare gli URL di pagina dal registro analizzato per chiamare la versione "extrastuff" dell'URL su localhost con un oggetto client web.

Aggiungi del codice per cambiare i file alla fine di ogni periodo di registro o riavvia il processo ogni periodo di registro.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.