Eseguire più worker role in un'unica istanza di un Cloud Service di Windows Azure

di Cristian Civera, in Windows Azure,

I Cloud Service di Windows Azure consentono due tipologie di applicazioni che possiamo ospitare ed eseguire all'interno delle macchine virtuali: web e worker role. Abbiamo già visto nello script #310, come tale distinzione sta solo nel decidere se necessitiamo di un sito IIS, poiché possiamo eseguire codice in background su entrambi i ruoli.

Il concetto di role fa naturalmente pensare di inserire una sola attività nel worker role, ma ci sono situazioni in cui il codice da eseguire è così banale, oppure che le esigenze non sono ancora tali da giustificare più macchine per eseguire altrettanti worker role. In questo caso, possiamo predisporre le nostre attività in più assembly o in più componenti, in modo da tenerli ben distinti e facili da utilizzare con ruoli differenti o assieme su uno stesso ruolo.

Nello script seguente ipotizziamo di rappresentare tutti i nostri componenti di lavoro con un'interfaccia.

public interface IWorkerAgent
{
    void Run();
    void Stop();
}

L'interfaccia definisce un metodo Run che, allo stesso modo di un worker role, nella sua implementazione deve ciclare o usare timer in base alle sue esigenze, come nell'esempio.

public class WorkerAgent1 : IWorkerAgent
{
    private bool cancel;

    public void Run()
    {
        // Continuo fino a quando OnStop non viene chiamato
        while (!cancel)
        {
            // TODO: faccio qualcosa

            // Aspetto un minuto
            Thread.Sleep(TimeSpan.FromMinutes(1));
        }
    }

    public void OnStop()
    {
        cancel = true;
    }
}

Definiti i vari componenti possiamo optare per usarne uno per ogni worker role, oppure usarli contemporaneamente in un'unica istanza. Per farlo è necessario bloccare il thread principale del ruolo e creare n thread per ogni componente da avviare.

public class WebRole : RoleEntryPoint
{
    private Thread[] threads;
    private WorkerAgent1[] agents;

    public override void Run()
    {
        // Preparo i componenti da avviare
        agents = new[] {
            new WorkerAgent1()
        };

        // Creo i thread per ogni componente
        threads = new Thread[agents.Length];
        for (int x = 0; x < agents.Length; x++)
        {
            threads[x] = new Thread(agents[x].Run);
            threads[x].IsBackground = true;
            threads[x].Start();
        }

        // Aspetto che tutti i componenti abbiano finito
        foreach (Thread t in threads)
            t.Join();
    }

    public override void OnStop()
    {
        try
        {
            // Segnalo di fermarsi
            foreach (IWorkerAgent a in agents)
                a.Stop();

            // Dò il tempo di fermare l'attività
            Thread.Sleep(1000);

            // Forzo abortendo i thread
            foreach (Thread t in threads)
                t.Abort();
        }
        catch (Exception)
        {}

        base.OnStop();
    }

}

Come possiamo vedere creiamo una lista dei componenti e una dei thread associati, aspettandoli per non far terminare il metodo principale Run. Nel caso di Stop, invece, notifichiamo ogni agent e abortiamo i thread per essere sicuri che si fermino.

Questa tecnica è comoda quando si vuole ottimizzare le risorse impiegate sulla piattaforma Windows Azure, ma ha il punto debole di non offrire scalabilità, se non è stata pensata su ogni componente. Creare due istanze dello stesso worker role, moltiplicherebbe anche i componenti che lavorano, dandoci risultati inattesi. In questo caso, allora, sarebbe meglio valutare l'adozione di un worker role per ogni componente.

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi