2012-06-07 6 views
6

È possibile eseguire un thread dal metodo WebRole.cs OnStart() in modo tale che siamo in grado di accedervi tramite la pagina aspx per eseguire il lavoro in background? So che il modo corretto per farlo sarebbe utilizzare un ruolo di lavoratore, ma vorrei mantenere i costi di gestione più bassi possibile.thread di sottofondo in Web Role di Azure

L'idea sarebbe quella di creare un thread che sarebbe sempre in esecuzione e in attesa di un lavoro, ad esempio se voglio fare un'operazione di blocco come l'invio di una e-mail vorrei usare il thread che dà il metodo SendEmail, è possibile fare? Se sì, puoi fornirmi alcuni esempi che potrebbero indicarmi la giusta direzione?

+0

Come vorrei che ridurre i costi di gestione? In che modo ciò che desideri è diverso dal singolo servizio di concorrenza a istanza singola? – Paparazzi

+3

@Blam: l'esecuzione di attività in background in un ruolo Web consente di unire le operazioni in un unico set di istanze VM. Ciò è in contrasto con l'inserimento delle operazioni in background in un set separato di istanze di ruolo. La combinazione in un ruolo consente di risparmiare costi, poiché ogni ruolo deve avere almeno un'istanza in esecuzione. Per i siti con volumi ridotti, questa è una grande architettura a basso costo.Se c'è il rischio che i task in background facciano la fame nel sito Web, o se sia necessario scalare separatamente le attività front-end e in background (o avere esigenze di dimensioni diverse della macchina virtuale), vale la pena considerare il passaggio a un ruolo separato. –

+0

@DavidMakogon Grazie Non sapevo che un ruolo operaio richiedesse un'istanza separata. E non ho provato a rispondere alla domanda. +1 Ho imparato molto da questa domanda. – Paparazzi

risposta

10

avrei suggets una soluzione che è diversa dalla soluzione Leon e David: soluzione

  • di David è male, ma non è resiliente. Che cosa l'istanza/processo va offline durante l'elaborazione dell'attività?
  • La soluzione di Leon si applica principalmente ai lavori programmati, ma l'invio di una e-mail non è sempre qualcosa che è in programma (forse si desidera inviare una e-mail quando qualcuno si registra nella tua app).

Un'altra opzione che si dovrebbe guardare sta utilizzando Azure code di Windows (sono molto a buon mercato) in questo scenario:

  • L'applicazione web: invia messaggi alla coda (come 'inviare una mail a [email protected] ')
  • WebRole.cs: genera un nuovo thread all'avvio dell'istanza e fa in modo che ascolti i messaggi da quella coda. Ogni volta che arriva un messaggio, elaboralo. In caso di successo, rimuovere il messaggio dalla coda.

Questa soluzione ha molti vantaggi. WebRole.cs viene eseguito in un processo diverso rispetto all'applicazione Web, quindi non c'è alcun impatto sui thread di richiesta. Inoltre, se l'invio della posta non riesce per qualsiasi motivo, il messaggio rimarrà in coda e verrà elaborato la volta successiva. Ciò assicurerà che non perderai nessuna attività da eseguire se l'applicazione o il processo si bloccano.

Ecco un esempio per iniziare. Si noti che è necessario migliorare questo codice se si vuole che sia pronto per la produzione (la politica, la gestione delle eccezioni, backoff polling, ... ritentare):

using System; 
using System.Collections.Generic; 
using System.Linq; 
using Microsoft.WindowsAzure; 
using Microsoft.WindowsAzure.Diagnostics; 
using Microsoft.WindowsAzure.ServiceRuntime; 
using Microsoft.WindowsAzure.StorageClient; 
using System.Threading.Tasks; 

namespace MvcWebRole1 
{ 
    public class WebRole : RoleEntryPoint 
    { 
     public override bool OnStart() 
     { 
      Task.Factory.StartNew(InitializeQueueListener); 
      return base.OnStart(); 
     } 

     private void InitializeQueueListener() 
     { 
      Microsoft.WindowsAzure.CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) => 
      { 
       configSetter(Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.GetConfigurationSettingValue(configName)); 
      }); 


      var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString"); 
      var queueStorage = storageAccount.CreateCloudQueueClient(); 
      var queue = queueStorage.GetQueueReference("myqueue"); 
      queue.CreateIfNotExist(); 

      while (true) 
      { 
       CloudQueueMessage msg = queue.GetMessage(); 
       if (msg != null) 
       { 
        // DO SOMETHING HERE 
        queue.DeleteMessage(msg); 
       } 
       else 
       { 
        System.Threading.Thread.Sleep(1000); 
       } 
      } 
     } 
    } 
} 
+0

Sembra una soluzione migliore per il tipo di lavoro che sono disposto a svolgere, comunque stavo pensando di avere code per "parlare" con un'applicazione locale, quindi non sarà così costoso ... Puoi approfondire ulteriormente come "generare un nuovo thread all'avvio dell'istanza e farlo ascoltare per i messaggi da quella coda"? ** Sarebbe fantastico se potessi darmi un esempio o indicarmi un esempio che spieghi la parte di thread coinvolta nell'avvio di un thread di ascolto in WebRole.cs **. Grazie – ToinoBiclas

+0

concordato - le code sono molto resilienti. Il mio intento era di sottolineare la fattibilità della creazione di thread (che non è sempre ovvio). –

+0

@Sandrino Fammi sapere se questo è in linea con la tua soluzione ... crea un thread in WebRole.OnStart() 'new Thread (new ThreadStart (ClassListeningToQueue.Method0)' quindi all'interno di Method0 scrivi un ciclo infinito o un ciclo con una condizione che cambia solo tramite WebRole.OnStop() 'while (true) {try {CloudQueueMessage msg = queue.GetMessage(); if (msg! = null) {' esegue in modo preciso l'attività in base ai valori all'interno del msg, ad esempio potrei avere un campo che indica quale metodo chiamare e anche i parametri.È sicuro chiamare altri thread all'interno del thread principale? – ToinoBiclas

1

ho trovato questo quando ero alla ricerca di "operazioni pianificate azzurro": http://www.ronaldwidha.net/2011/02/23/cron-job-on-azure-using-scheduled-task-on-a-web-role-to-replace-azure-worker-role-for-background-job/

sembra esattamente quello che stai cercando.

+0

L'esempio che hai indicato è per l'esecuzione di lavori programmati, proprio come crontabs in Linux. Quello che sono disposto a fare è avere un thread in attesa di essere segnalato. – ToinoBiclas

+0

E 'solo per sottolineare che è sicuramente possibile fare questo genere di cose. Immagino che tu possa trovare una soluzione con un po 'di creatività. –

2

Assolutamente è possibile creare una discussione (o molte di esse). Un ruolo Web è fondamentalmente Windows 2008 Server. Non è necessario un ruolo di lavoro separato solo per impostare un'attività in background. Naturalmente, il numeropuò avere un ruolo di lavoro separato, che consente di ridimensionare tali istanze indipendentemente dalle istanze del ruolo Web. È qui che dovrai bilanciare le prestazioni/il ridimensionamento con i costi.

+0

Puoi darmi qualche dettaglio su come farlo? Come posso accedere alla variabile thread da una delle pagine Web di aspx se è stata dichiarata nella WebRole: RoleEntryPoint? – ToinoBiclas

+2

Se è necessario interagire con i thread delle pagine aspx, perché non avviare i thread da global.asax? RoleEntryPoint verrà eseguito in un AppDomain separato in modo da non avere interazione tra app e thread. –

+0

Onestamente non ci ho mai pensato. Proverò a fare qualche test con un pool di thread dichiarato in global.asax. – ToinoBiclas